int dns_name_normalize(const char *s, char **_ret) { _cleanup_free_ char *ret = NULL; size_t n = 0, allocated = 0; const char *p = s; bool first = true; int r; assert(s); for (;;) { _cleanup_free_ char *t = NULL; char label[DNS_LABEL_MAX]; int k; r = dns_label_unescape(&p, label, sizeof(label)); if (r < 0) return r; if (r == 0) { if (*p != 0) return -EINVAL; break; } k = dns_label_undo_idna(label, r, label, sizeof(label)); if (k < 0) return k; if (k > 0) r = k; r = dns_label_escape(label, r, &t); if (r < 0) return r; if (!GREEDY_REALLOC(ret, allocated, n + !first + strlen(t) + 1)) return -ENOMEM; if (!first) ret[n++] = '.'; else first = false; memcpy(ret + n, t, r); n += r; } if (n > DNS_NAME_MAX) return -EINVAL; if (!GREEDY_REALLOC(ret, allocated, n + 1)) return -ENOMEM; ret[n] = 0; if (_ret) { *_ret = ret; ret = NULL; } return 0; }
static int network_link_get_ifindexes(int ifindex, const char *key, int **ret) { char path[strlen("/run/systemd/netif/links/") + DECIMAL_STR_MAX(ifindex) + 1]; _cleanup_free_ int *ifis = NULL; _cleanup_free_ char *s = NULL; size_t allocated = 0, c = 0; const char *x; int r; assert_return(ifindex > 0, -EINVAL); assert_return(ret, -EINVAL); xsprintf(path, "/run/systemd/netif/links/%i", ifindex); r = parse_env_file(path, NEWLINE, key, &s, NULL); if (r == -ENOENT) return -ENODATA; if (r < 0) return r; if (isempty(s)) { *ret = NULL; return 0; } x = s; for (;;) { _cleanup_free_ char *word = NULL; r = extract_first_word(&x, &word, NULL, 0); if (r < 0) return r; if (r == 0) break; r = parse_ifindex(word, &ifindex); if (r < 0) return r; if (!GREEDY_REALLOC(ifis, allocated, c + 1)) return -ENOMEM; ifis[c++] = ifindex; } if (!GREEDY_REALLOC(ifis, allocated, c + 1)) return -ENOMEM; ifis[c] = 0; /* Let's add a 0 ifindex to the end, to be nice*/ *ret = ifis; ifis = NULL; return c; }
static int iovw_put(struct iovec_wrapper *iovw, void* data, size_t len) { if (!GREEDY_REALLOC(iovw->iovec, iovw->size_bytes, iovw->count + 1)) return log_oom(); iovw->iovec[iovw->count++] = IOVEC_MAKE(data, len); return 0; }
int sd_dhcp_client_set_request_option(sd_dhcp_client *client, uint8_t option) { size_t i; assert_return(client, -EINVAL); assert_return (IN_SET(client->state, DHCP_STATE_INIT, DHCP_STATE_STOPPED), -EBUSY); switch(option) { case DHCP_OPTION_PAD: case DHCP_OPTION_OVERLOAD: case DHCP_OPTION_MESSAGE_TYPE: case DHCP_OPTION_PARAMETER_REQUEST_LIST: case DHCP_OPTION_END: return -EINVAL; default: break; } for (i = 0; i < client->req_opts_size; i++) if (client->req_opts[i] == option) return -EEXIST; if (!GREEDY_REALLOC(client->req_opts, client->req_opts_allocated, client->req_opts_size + 1)) return -ENOMEM; client->req_opts[client->req_opts_size++] = option; return 0; }
int get_timezones(char ***ret) { _cleanup_fclose_ FILE *f = NULL; _cleanup_strv_free_ char **zones = NULL; size_t n_zones = 0, n_allocated = 0; assert(ret); zones = strv_new("UTC", NULL); if (!zones) return -ENOMEM; n_allocated = 2; n_zones = 1; f = fopen("/usr/share/zoneinfo/zone.tab", "re"); if (f) { char l[LINE_MAX]; FOREACH_LINE(l, f, return -errno) { char *p, *w; size_t k; p = strstrip(l); if (isempty(p) || *p == '#') continue; /* Skip over country code */ p += strcspn(p, WHITESPACE); p += strspn(p, WHITESPACE); /* Skip over coordinates */ p += strcspn(p, WHITESPACE); p += strspn(p, WHITESPACE); /* Found timezone name */ k = strcspn(p, WHITESPACE); if (k <= 0) continue; w = strndup(p, k); if (!w) return -ENOMEM; if (!GREEDY_REALLOC(zones, n_allocated, n_zones + 2)) { free(w); return -ENOMEM; } zones[n_zones++] = w; zones[n_zones] = NULL; } strv_sort(zones); } else if (errno != ENOENT)
static char* realloc_buffer(RemoteSource *source, size_t size) { char *b, *old = source->buf; b = GREEDY_REALLOC(source->buf, source->size, size); if (!b) return NULL; iovw_rebase(&source->iovw, old, source->buf); return b; }
static int stdout_stream_process(sd_event_source *es, int fd, uint32_t revents, void *userdata) { StdoutStream *s = userdata; size_t limit; ssize_t l; int r; assert(s); if ((revents|EPOLLIN|EPOLLHUP) != (EPOLLIN|EPOLLHUP)) { log_error("Got invalid event from epoll for stdout stream: %"PRIx32, revents); goto terminate; } /* If the buffer is full already (discounting the extra NUL we need), add room for another 1K */ if (s->length + 1 >= s->allocated) { if (!GREEDY_REALLOC(s->buffer, s->allocated, s->length + 1 + 1024)) { log_oom(); goto terminate; } } /* Try to make use of the allocated buffer in full, but never read more than the configured line size. Also, * always leave room for a terminating NUL we might need to add. */ limit = MIN(s->allocated - 1, s->server->line_max); l = read(s->fd, s->buffer + s->length, limit - s->length); if (l < 0) { if (errno == EAGAIN) return 0; log_warning_errno(errno, "Failed to read from stream: %m"); goto terminate; } if (l == 0) { stdout_stream_scan(s, true); goto terminate; } s->length += l; r = stdout_stream_scan(s, false); if (r < 0) goto terminate; return 1; terminate: stdout_stream_destroy(s); return 0; }
static int decode_and_sort_links(sd_netlink_message *m, LinkInfo **ret) { _cleanup_free_ LinkInfo *links = NULL; size_t size = 0, c = 0; sd_netlink_message *i; int r; for (i = m; i; i = sd_netlink_message_next(i)) { const char *name; unsigned iftype; uint16_t type; int ifindex; r = sd_netlink_message_get_type(i, &type); if (r < 0) return r; if (type != RTM_NEWLINK) continue; r = sd_rtnl_message_link_get_ifindex(i, &ifindex); if (r < 0) return r; r = sd_netlink_message_read_string(i, IFLA_IFNAME, &name); if (r < 0) return r; r = sd_rtnl_message_link_get_type(i, &iftype); if (r < 0) return r; if (!GREEDY_REALLOC(links, size, c+1)) return -ENOMEM; links[c].name = name; links[c].ifindex = ifindex; links[c].iftype = iftype; c++; } qsort_safe(links, c, sizeof(LinkInfo), link_info_compare); *ret = links; links = NULL; return (int) c; }
static int radv_get_ip6dns(Network *network, struct in6_addr **dns, size_t *n_dns) { _cleanup_free_ struct in6_addr *addresses = NULL; size_t i, n_addresses = 0, n_allocated = 0; assert(network); assert(dns); assert(n_dns); for (i = 0; i < network->n_dns; i++) { union in_addr_union *addr; if (network->dns[i].family != AF_INET6) continue; addr = &network->dns[i].address; if (in_addr_is_null(AF_INET6, addr) || in_addr_is_link_local(AF_INET6, addr) || in_addr_is_localhost(AF_INET6, addr)) continue; if (!GREEDY_REALLOC(addresses, n_allocated, n_addresses + 1)) return -ENOMEM; addresses[n_addresses++] = addr->in6; } if (addresses) { *dns = addresses; addresses = NULL; *n_dns = n_addresses; } return n_addresses; }
int bus_image_node_enumerator(sd_bus *bus, const char *path, void *userdata, char ***nodes, sd_bus_error *error) { _cleanup_hashmap_free_ Hashmap *images = NULL; _cleanup_strv_free_ char **l = NULL; size_t n_allocated = 0, n = 0; Manager *m = userdata; Image *image; Iterator i; int r; assert(bus); assert(path); assert(nodes); images = hashmap_new(&image_hash_ops); if (!images) return -ENOMEM; r = manager_image_cache_discover(m, images, error); if (r < 0) return r; HASHMAP_FOREACH(image, images, i) { char *p; r = bus_image_path(image, &p); if (r < 0) return r; if (!GREEDY_REALLOC(l, n_allocated, n+2)) { free(p); return -ENOMEM; } l[n++] = p; l[n] = NULL; }
int bus_creds_add_more(sd_bus_creds *c, uint64_t mask, pid_t pid, pid_t tid) { uint64_t missing; int r; assert(c); assert(c->allocated); if (!(mask & SD_BUS_CREDS_AUGMENT)) return 0; /* Try to retrieve PID from creds if it wasn't passed to us */ if (pid > 0) { c->pid = pid; c->mask |= SD_BUS_CREDS_PID; } else if (c->mask & SD_BUS_CREDS_PID) pid = c->pid; else /* Without pid we cannot do much... */ return 0; /* Try to retrieve TID from creds if it wasn't passed to us */ if (tid <= 0 && (c->mask & SD_BUS_CREDS_TID)) tid = c->tid; /* Calculate what we shall and can add */ missing = mask & ~(c->mask|SD_BUS_CREDS_PID|SD_BUS_CREDS_TID|SD_BUS_CREDS_UNIQUE_NAME|SD_BUS_CREDS_WELL_KNOWN_NAMES|SD_BUS_CREDS_DESCRIPTION|SD_BUS_CREDS_AUGMENT); if (missing == 0) return 0; if (tid > 0) { c->tid = tid; c->mask |= SD_BUS_CREDS_TID; } if (missing & (SD_BUS_CREDS_PPID | SD_BUS_CREDS_UID | SD_BUS_CREDS_EUID | SD_BUS_CREDS_SUID | SD_BUS_CREDS_FSUID | SD_BUS_CREDS_GID | SD_BUS_CREDS_EGID | SD_BUS_CREDS_SGID | SD_BUS_CREDS_FSGID | SD_BUS_CREDS_SUPPLEMENTARY_GIDS | SD_BUS_CREDS_EFFECTIVE_CAPS | SD_BUS_CREDS_INHERITABLE_CAPS | SD_BUS_CREDS_PERMITTED_CAPS | SD_BUS_CREDS_BOUNDING_CAPS)) { _cleanup_fclose_ FILE *f = NULL; const char *p; p = procfs_file_alloca(pid, "status"); f = fopen(p, "re"); if (!f) { if (errno == ENOENT) return -ESRCH; else if (errno != EPERM && errno != EACCES) return -errno; } else { char line[LINE_MAX]; FOREACH_LINE(line, f, return -errno) { truncate_nl(line); if (missing & SD_BUS_CREDS_PPID) { p = startswith(line, "PPid:"); if (p) { p += strspn(p, WHITESPACE); /* Explicitly check for PPID 0 (which is the case for PID 1) */ if (!streq(p, "0")) { r = parse_pid(p, &c->ppid); if (r < 0) return r; } else c->ppid = 0; c->mask |= SD_BUS_CREDS_PPID; continue; } } if (missing & (SD_BUS_CREDS_UID|SD_BUS_CREDS_EUID|SD_BUS_CREDS_SUID|SD_BUS_CREDS_FSUID)) { p = startswith(line, "Uid:"); if (p) { unsigned long uid, euid, suid, fsuid; p += strspn(p, WHITESPACE); if (sscanf(p, "%lu %lu %lu %lu", &uid, &euid, &suid, &fsuid) != 4) return -EIO; if (missing & SD_BUS_CREDS_UID) c->uid = (uid_t) uid; if (missing & SD_BUS_CREDS_EUID) c->euid = (uid_t) euid; if (missing & SD_BUS_CREDS_SUID) c->suid = (uid_t) suid; if (missing & SD_BUS_CREDS_FSUID) c->fsuid = (uid_t) fsuid; c->mask |= missing & (SD_BUS_CREDS_UID|SD_BUS_CREDS_EUID|SD_BUS_CREDS_SUID|SD_BUS_CREDS_FSUID); continue; } } if (missing & (SD_BUS_CREDS_GID|SD_BUS_CREDS_EGID|SD_BUS_CREDS_SGID|SD_BUS_CREDS_FSGID)) { p = startswith(line, "Gid:"); if (p) { unsigned long gid, egid, sgid, fsgid; p += strspn(p, WHITESPACE); if (sscanf(p, "%lu %lu %lu %lu", &gid, &egid, &sgid, &fsgid) != 4) return -EIO; if (missing & SD_BUS_CREDS_GID) c->gid = (gid_t) gid; if (missing & SD_BUS_CREDS_EGID) c->egid = (gid_t) egid; if (missing & SD_BUS_CREDS_SGID) c->sgid = (gid_t) sgid; if (missing & SD_BUS_CREDS_FSGID) c->fsgid = (gid_t) fsgid; c->mask |= missing & (SD_BUS_CREDS_GID|SD_BUS_CREDS_EGID|SD_BUS_CREDS_SGID|SD_BUS_CREDS_FSGID); continue; } } if (missing & SD_BUS_CREDS_SUPPLEMENTARY_GIDS) { p = startswith(line, "Groups:"); if (p) { size_t allocated = 0; for (;;) { unsigned long g; int n = 0; p += strspn(p, WHITESPACE); if (*p == 0) break; if (sscanf(p, "%lu%n", &g, &n) != 1) return -EIO; if (!GREEDY_REALLOC(c->supplementary_gids, allocated, c->n_supplementary_gids+1)) return -ENOMEM; c->supplementary_gids[c->n_supplementary_gids++] = (gid_t) g; p += n; } c->mask |= SD_BUS_CREDS_SUPPLEMENTARY_GIDS; continue; } } if (missing & SD_BUS_CREDS_EFFECTIVE_CAPS) { p = startswith(line, "CapEff:"); if (p) { r = parse_caps(c, CAP_OFFSET_EFFECTIVE, p); if (r < 0) return r; c->mask |= SD_BUS_CREDS_EFFECTIVE_CAPS; continue; } } if (missing & SD_BUS_CREDS_PERMITTED_CAPS) { p = startswith(line, "CapPrm:"); if (p) { r = parse_caps(c, CAP_OFFSET_PERMITTED, p); if (r < 0) return r; c->mask |= SD_BUS_CREDS_PERMITTED_CAPS; continue; } } if (missing & SD_BUS_CREDS_INHERITABLE_CAPS) { p = startswith(line, "CapInh:"); if (p) { r = parse_caps(c, CAP_OFFSET_INHERITABLE, p); if (r < 0) return r; c->mask |= SD_BUS_CREDS_INHERITABLE_CAPS; continue; } } if (missing & SD_BUS_CREDS_BOUNDING_CAPS) { p = startswith(line, "CapBnd:"); if (p) { r = parse_caps(c, CAP_OFFSET_BOUNDING, p); if (r < 0) return r; c->mask |= SD_BUS_CREDS_BOUNDING_CAPS; continue; } } } } }
int journal_directory_vacuum( const char *directory, uint64_t max_use, uint64_t n_max_files, usec_t max_retention_usec, usec_t *oldest_usec, bool verbose) { _cleanup_closedir_ DIR *d = NULL; struct vacuum_info *list = NULL; unsigned n_list = 0, i, n_active_files = 0; size_t n_allocated = 0; uint64_t sum = 0, freed = 0; usec_t retention_limit = 0; char sbytes[FORMAT_BYTES_MAX]; struct dirent *de; int r; assert(directory); if (max_use <= 0 && max_retention_usec <= 0 && n_max_files <= 0) return 0; if (max_retention_usec > 0) { retention_limit = now(CLOCK_REALTIME); if (retention_limit > max_retention_usec) retention_limit -= max_retention_usec; else max_retention_usec = retention_limit = 0; } d = opendir(directory); if (!d) return -errno; FOREACH_DIRENT_ALL(de, d, r = -errno; goto finish) { unsigned long long seqnum = 0, realtime; _cleanup_free_ char *p = NULL; sd_id128_t seqnum_id; bool have_seqnum; uint64_t size; struct stat st; size_t q; if (fstatat(dirfd(d), de->d_name, &st, AT_SYMLINK_NOFOLLOW) < 0) { log_debug_errno(errno, "Failed to stat file %s while vacuuming, ignoring: %m", de->d_name); continue; } if (!S_ISREG(st.st_mode)) continue; q = strlen(de->d_name); if (endswith(de->d_name, ".journal")) { /* Vacuum archived files. Active files are * left around */ if (q < 1 + 32 + 1 + 16 + 1 + 16 + 8) { n_active_files++; continue; } if (de->d_name[q-8-16-1] != '-' || de->d_name[q-8-16-1-16-1] != '-' || de->d_name[q-8-16-1-16-1-32-1] != '@') { n_active_files++; continue; } p = strdup(de->d_name); if (!p) { r = -ENOMEM; goto finish; } de->d_name[q-8-16-1-16-1] = 0; if (sd_id128_from_string(de->d_name + q-8-16-1-16-1-32, &seqnum_id) < 0) { n_active_files++; continue; } if (sscanf(de->d_name + q-8-16-1-16, "%16llx-%16llx.journal", &seqnum, &realtime) != 2) { n_active_files++; continue; } have_seqnum = true; } else if (endswith(de->d_name, ".journal~")) { unsigned long long tmp; /* Vacuum corrupted files */ if (q < 1 + 16 + 1 + 16 + 8 + 1) { n_active_files ++; continue; } if (de->d_name[q-1-8-16-1] != '-' || de->d_name[q-1-8-16-1-16-1] != '@') { n_active_files ++; continue; } p = strdup(de->d_name); if (!p) { r = -ENOMEM; goto finish; } if (sscanf(de->d_name + q-1-8-16-1-16, "%16llx-%16llx.journal~", &realtime, &tmp) != 2) { n_active_files ++; continue; } have_seqnum = false; } else { /* We do not vacuum unknown files! */ log_debug("Not vacuuming unknown file %s.", de->d_name); continue; } size = 512UL * (uint64_t) st.st_blocks; r = journal_file_empty(dirfd(d), p); if (r < 0) { log_debug_errno(r, "Failed check if %s is empty, ignoring: %m", p); continue; } if (r > 0) { /* Always vacuum empty non-online files. */ if (unlinkat(dirfd(d), p, 0) >= 0) { log_full(verbose ? LOG_INFO : LOG_DEBUG, "Deleted empty archived journal %s/%s (%s).", directory, p, format_bytes(sbytes, sizeof(sbytes), size)); freed += size; } else if (errno != ENOENT) log_warning_errno(errno, "Failed to delete empty archived journal %s/%s: %m", directory, p); continue; } patch_realtime(dirfd(d), p, &st, &realtime); if (!GREEDY_REALLOC(list, n_allocated, n_list + 1)) { r = -ENOMEM; goto finish; } list[n_list].filename = p; list[n_list].usage = size; list[n_list].seqnum = seqnum; list[n_list].realtime = realtime; list[n_list].seqnum_id = seqnum_id; list[n_list].have_seqnum = have_seqnum; n_list ++; p = NULL; sum += size; } qsort_safe(list, n_list, sizeof(struct vacuum_info), vacuum_compare); for (i = 0; i < n_list; i++) { unsigned left; left = n_active_files + n_list - i; if ((max_retention_usec <= 0 || list[i].realtime >= retention_limit) && (max_use <= 0 || sum <= max_use) && (n_max_files <= 0 || left <= n_max_files)) break; if (unlinkat(dirfd(d), list[i].filename, 0) >= 0) { log_full(verbose ? LOG_INFO : LOG_DEBUG, "Deleted archived journal %s/%s (%s).", directory, list[i].filename, format_bytes(sbytes, sizeof(sbytes), list[i].usage)); freed += list[i].usage; if (list[i].usage < sum) sum -= list[i].usage; else sum = 0; } else if (errno != ENOENT) log_warning_errno(errno, "Failed to delete archived journal %s/%s: %m", directory, list[i].filename); } if (oldest_usec && i < n_list && (*oldest_usec == 0 || list[i].realtime < *oldest_usec)) *oldest_usec = list[i].realtime; r = 0; finish: for (i = 0; i < n_list; i++) free(list[i].filename); free(list); log_full(verbose ? LOG_INFO : LOG_DEBUG, "Vacuuming done, freed %s of archived journals on disk.", format_bytes(sbytes, sizeof(sbytes), freed)); return r; }
int main(int argc, char* argv[]) { int r, j = 0; char *t; ssize_t n; pid_t pid; uid_t uid; gid_t gid; struct iovec iovec[14]; size_t coredump_bufsize, coredump_size; _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, *coredump_data = 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; } coredump_bufsize = COREDUMP_MIN_START; coredump_data = malloc(coredump_bufsize); if (!coredump_data) { r = log_oom(); goto finish; } memcpy(coredump_data, "COREDUMP=", 9); coredump_size = 9; for (;;) { n = loop_read(STDIN_FILENO, coredump_data + coredump_size, coredump_bufsize - coredump_size, false); if (n < 0) { log_error("Failed to read core dump data: %s", strerror(-n)); r = (int) n; goto finish; } else if (n == 0) break; coredump_size += n; if (!GREEDY_REALLOC(coredump_data, coredump_bufsize, coredump_size + 1)) { r = log_oom(); goto finish; } } iovec[j].iov_base = coredump_data; iovec[j].iov_len = coredump_size; 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; }
static int server_process_entry( Server *s, const void *buffer, size_t *remaining, ClientContext *context, const struct ucred *ucred, const struct timeval *tv, const char *label, size_t label_len) { /* Process a single entry from a native message. * Returns 0 if nothing special happened and the message processing should continue, * and a negative or positive value otherwise. * * Note that *remaining is altered on both success and failure. */ struct iovec *iovec = NULL; unsigned n = 0, j, tn = (unsigned) -1; const char *p; size_t m = 0, entry_size = 0; int priority = LOG_INFO; char *identifier = NULL, *message = NULL; pid_t object_pid = 0; int r = 0; p = buffer; while (*remaining > 0) { const char *e, *q; e = memchr(p, '\n', *remaining); if (!e) { /* Trailing noise, let's ignore it, and flush what we collected */ log_debug("Received message with trailing noise, ignoring."); r = 1; /* finish processing of the message */ break; } if (e == p) { /* Entry separator */ *remaining -= 1; break; } if (*p == '.' || *p == '#') { /* Ignore control commands for now, and * comments too. */ *remaining -= (e - p) + 1; p = e + 1; continue; } /* A property follows */ /* n existing properties, 1 new, +1 for _TRANSPORT */ if (!GREEDY_REALLOC(iovec, m, n + 2 + N_IOVEC_META_FIELDS + N_IOVEC_OBJECT_FIELDS)) { r = log_oom(); break; } q = memchr(p, '=', e - p); if (q) { if (valid_user_field(p, q - p, false)) { size_t l; l = e - p; /* If the field name starts with an * underscore, skip the variable, * since that indicates a trusted * field */ iovec[n].iov_base = (char*) p; iovec[n].iov_len = l; entry_size += l; n++; server_process_entry_meta(p, l, ucred, &priority, &identifier, &message, &object_pid); } *remaining -= (e - p) + 1; p = e + 1; continue; } else { uint64_t l; char *k; if (*remaining < e - p + 1 + sizeof(uint64_t) + 1) { log_debug("Failed to parse message, ignoring."); break; } l = unaligned_read_le64(e + 1); if (l > DATA_SIZE_MAX) { log_debug("Received binary data block of %"PRIu64" bytes is too large, ignoring.", l); break; } if ((uint64_t) *remaining < e - p + 1 + sizeof(uint64_t) + l + 1 || e[1+sizeof(uint64_t)+l] != '\n') { log_debug("Failed to parse message, ignoring."); break; } k = malloc((e - p) + 1 + l); if (!k) { log_oom(); break; } memcpy(k, p, e - p); k[e - p] = '='; memcpy(k + (e - p) + 1, e + 1 + sizeof(uint64_t), l); if (valid_user_field(p, e - p, false)) { iovec[n].iov_base = k; iovec[n].iov_len = (e - p) + 1 + l; entry_size += iovec[n].iov_len; n++; server_process_entry_meta(k, (e - p) + 1 + l, ucred, &priority, &identifier, &message, &object_pid); } else free(k); *remaining -= (e - p) + 1 + sizeof(uint64_t) + l + 1; p = e + 1 + sizeof(uint64_t) + l + 1; } } if (n <= 0) { r = 1; goto finish; } tn = n++; IOVEC_SET_STRING(iovec[tn], "_TRANSPORT=journal"); entry_size += strlen("_TRANSPORT=journal"); if (entry_size + n + 1 > ENTRY_SIZE_MAX) { /* data + separators + trailer */ log_debug("Entry is too big with %u properties and %zu bytes, ignoring.", n, entry_size); goto finish; } if (message) { if (s->forward_to_syslog) server_forward_syslog(s, syslog_fixup_facility(priority), identifier, message, ucred, tv); if (s->forward_to_kmsg) server_forward_kmsg(s, priority, identifier, message, ucred); if (s->forward_to_console) server_forward_console(s, priority, identifier, message, ucred); if (s->forward_to_wall) server_forward_wall(s, priority, identifier, message, ucred); } server_dispatch_message(s, iovec, n, m, context, tv, priority, object_pid); finish: for (j = 0; j < n; j++) { if (j == tn) continue; if (iovec[j].iov_base < buffer || (const char*) iovec[j].iov_base >= p + *remaining) free(iovec[j].iov_base); } free(iovec); free(identifier); free(message); return r; }
static int parse_env_file_internal( FILE *f, const char *fname, const char *newline, int (*push) (const char *filename, unsigned line, const char *key, char *value, void *userdata, int *n_pushed), void *userdata, int *n_pushed) { _cleanup_free_ char *contents = NULL, *key = NULL; size_t key_alloc = 0, n_key = 0, value_alloc = 0, n_value = 0, last_value_whitespace = (size_t) -1, last_key_whitespace = (size_t) -1; char *p, *value = NULL; int r; unsigned line = 1; enum { PRE_KEY, KEY, PRE_VALUE, VALUE, VALUE_ESCAPE, SINGLE_QUOTE_VALUE, SINGLE_QUOTE_VALUE_ESCAPE, DOUBLE_QUOTE_VALUE, DOUBLE_QUOTE_VALUE_ESCAPE, COMMENT, COMMENT_ESCAPE } state = PRE_KEY; assert(newline); if (f) r = read_full_stream(f, &contents, NULL); else r = read_full_file(fname, &contents, NULL); if (r < 0) return r; for (p = contents; *p; p++) { char c = *p; switch (state) { case PRE_KEY: if (strchr(COMMENTS, c)) state = COMMENT; else if (!strchr(WHITESPACE, c)) { state = KEY; last_key_whitespace = (size_t) -1; if (!GREEDY_REALLOC(key, key_alloc, n_key+2)) { r = -ENOMEM; goto fail; } key[n_key++] = c; } break; case KEY: if (strchr(newline, c)) { state = PRE_KEY; line++; n_key = 0; } else if (c == '=') { state = PRE_VALUE; last_value_whitespace = (size_t) -1; } else { if (!strchr(WHITESPACE, c)) last_key_whitespace = (size_t) -1; else if (last_key_whitespace == (size_t) -1) last_key_whitespace = n_key; if (!GREEDY_REALLOC(key, key_alloc, n_key+2)) { r = -ENOMEM; goto fail; } key[n_key++] = c; } break; case PRE_VALUE: if (strchr(newline, c)) { state = PRE_KEY; line++; key[n_key] = 0; if (value) value[n_value] = 0; /* strip trailing whitespace from key */ if (last_key_whitespace != (size_t) -1) key[last_key_whitespace] = 0; r = push(fname, line, key, value, userdata, n_pushed); if (r < 0) goto fail; n_key = 0; value = NULL; value_alloc = n_value = 0; } else if (c == '\'') state = SINGLE_QUOTE_VALUE; else if (c == '\"') state = DOUBLE_QUOTE_VALUE; else if (c == '\\') state = VALUE_ESCAPE; else if (!strchr(WHITESPACE, c)) { state = VALUE; if (!GREEDY_REALLOC(value, value_alloc, n_value+2)) { r = -ENOMEM; goto fail; } value[n_value++] = c; } break; case VALUE: if (strchr(newline, c)) { state = PRE_KEY; line++; key[n_key] = 0; if (value) value[n_value] = 0; /* Chomp off trailing whitespace from value */ if (last_value_whitespace != (size_t) -1) value[last_value_whitespace] = 0; /* strip trailing whitespace from key */ if (last_key_whitespace != (size_t) -1) key[last_key_whitespace] = 0; r = push(fname, line, key, value, userdata, n_pushed); if (r < 0) goto fail; n_key = 0; value = NULL; value_alloc = n_value = 0; } else if (c == '\\') { state = VALUE_ESCAPE; last_value_whitespace = (size_t) -1; } else { if (!strchr(WHITESPACE, c)) last_value_whitespace = (size_t) -1; else if (last_value_whitespace == (size_t) -1) last_value_whitespace = n_value; if (!GREEDY_REALLOC(value, value_alloc, n_value+2)) { r = -ENOMEM; goto fail; } value[n_value++] = c; } break; case VALUE_ESCAPE: state = VALUE; if (!strchr(newline, c)) { /* Escaped newlines we eat up entirely */ if (!GREEDY_REALLOC(value, value_alloc, n_value+2)) { r = -ENOMEM; goto fail; } value[n_value++] = c; } break; case SINGLE_QUOTE_VALUE: if (c == '\'') state = PRE_VALUE; else if (c == '\\') state = SINGLE_QUOTE_VALUE_ESCAPE; else { if (!GREEDY_REALLOC(value, value_alloc, n_value+2)) { r = -ENOMEM; goto fail; } value[n_value++] = c; } break; case SINGLE_QUOTE_VALUE_ESCAPE: state = SINGLE_QUOTE_VALUE; if (!strchr(newline, c)) { if (!GREEDY_REALLOC(value, value_alloc, n_value+2)) { r = -ENOMEM; goto fail; } value[n_value++] = c; } break; case DOUBLE_QUOTE_VALUE: if (c == '\"') state = PRE_VALUE; else if (c == '\\') state = DOUBLE_QUOTE_VALUE_ESCAPE; else { if (!GREEDY_REALLOC(value, value_alloc, n_value+2)) { r = -ENOMEM; goto fail; } value[n_value++] = c; } break; case DOUBLE_QUOTE_VALUE_ESCAPE: state = DOUBLE_QUOTE_VALUE; if (!strchr(newline, c)) { if (!GREEDY_REALLOC(value, value_alloc, n_value+2)) { r = -ENOMEM; goto fail; } value[n_value++] = c; } break; case COMMENT: if (c == '\\') state = COMMENT_ESCAPE; else if (strchr(newline, c)) { state = PRE_KEY; line++; } break; case COMMENT_ESCAPE: state = COMMENT; break; } } if (state == PRE_VALUE || state == VALUE || state == VALUE_ESCAPE || state == SINGLE_QUOTE_VALUE || state == SINGLE_QUOTE_VALUE_ESCAPE || state == DOUBLE_QUOTE_VALUE || state == DOUBLE_QUOTE_VALUE_ESCAPE) { key[n_key] = 0; if (value) value[n_value] = 0; if (state == VALUE) if (last_value_whitespace != (size_t) -1) value[last_value_whitespace] = 0; /* strip trailing whitespace from key */ if (last_key_whitespace != (size_t) -1) key[last_key_whitespace] = 0; r = push(fname, line, key, value, userdata, n_pushed); if (r < 0) goto fail; } return 0; fail: free(value); return r; }
static int json_tokens(const char *string, size_t size, JsonVariant ***tokens, size_t *n) { _cleanup_free_ char *buf = NULL; _cleanup_(json_variant_array_unrefp) JsonVariant **items = NULL; union json_value v = {}; void *json_state = NULL; const char *p; int t, r; size_t allocated = 0, s = 0; assert(string); assert(n); if (size <= 0) return -EBADMSG; buf = strndup(string, size); if (!buf) return -ENOMEM; p = buf; for (;;) { _cleanup_json_variant_unref_ JsonVariant *var = NULL; _cleanup_free_ char *rstr = NULL; t = json_tokenize(&p, &rstr, &v, &json_state, NULL); if (t < 0) return t; else if (t == JSON_END) break; if (t <= JSON_ARRAY_CLOSE) { r = json_variant_new(&var, JSON_VARIANT_CONTROL); if (r < 0) return r; var->value.integer = t; } else { switch (t) { case JSON_STRING: r = json_variant_new(&var, JSON_VARIANT_STRING); if (r < 0) return r; var->size = strlen(rstr); var->string = strdup(rstr); if (!var->string) { return -ENOMEM; } break; case JSON_INTEGER: r = json_variant_new(&var, JSON_VARIANT_INTEGER); if (r < 0) return r; var->value = v; break; case JSON_REAL: r = json_variant_new(&var, JSON_VARIANT_REAL); if (r < 0) return r; var->value = v; break; case JSON_BOOLEAN: r = json_variant_new(&var, JSON_VARIANT_BOOLEAN); if (r < 0) return r; var->value = v; break; case JSON_NULL: r = json_variant_new(&var, JSON_VARIANT_NULL); if (r < 0) return r; break; } } if (!GREEDY_REALLOC(items, allocated, s+2)) return -ENOMEM; items[s++] = var; items[s] = NULL; var = NULL; } *n = s; *tokens = items; items = NULL; return 0; }
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 bus_match_parse( const char *match, struct bus_match_component **_components, unsigned *_n_components) { const char *p = match; struct bus_match_component *components = NULL; size_t components_allocated = 0; unsigned n_components = 0, i; _cleanup_free_ char *value = NULL; int r; assert(match); assert(_components); assert(_n_components); while (*p != 0) { const char *eq, *q; enum bus_match_node_type t; unsigned j = 0; size_t value_allocated = 0; bool escaped = false; uint8_t u; eq = strchr(p, '='); if (!eq) return -EINVAL; if (eq[1] != '\'') return -EINVAL; t = bus_match_node_type_from_string(p, eq - p); if (t < 0) return -EINVAL; for (q = eq + 2;; q++) { if (*q == 0) { r = -EINVAL; goto fail; } if (!escaped) { if (*q == '\\') { escaped = true; continue; } if (*q == '\'') { if (value) value[j] = 0; break; } } if (!GREEDY_REALLOC(value, value_allocated, j + 2)) { r = -ENOMEM; goto fail; } value[j++] = *q; escaped = false; } if (t == BUS_MATCH_MESSAGE_TYPE) { r = bus_message_type_from_string(value, &u); if (r < 0) goto fail; free(value); value = NULL; } else u = 0; if (!GREEDY_REALLOC(components, components_allocated, n_components + 1)) { r = -ENOMEM; goto fail; } components[n_components].type = t; components[n_components].value_str = value; components[n_components].value_u8 = u; n_components++; value = NULL; if (q[1] == 0) break; if (q[1] != ',') { r = -EINVAL; goto fail; } p = q + 2; } /* Order the whole thing, so that we always generate the same tree */ qsort_safe(components, n_components, sizeof(struct bus_match_component), match_component_compare); /* Check for duplicates */ for (i = 0; i+1 < n_components; i++) if (components[i].type == components[i+1].type) { r = -EINVAL; goto fail; } *_components = components; *_n_components = n_components; return 0; fail: bus_match_parse_free(components, n_components); return r; }
static int json_parse_string(const char **p, char **ret) { _cleanup_free_ char *s = NULL; size_t n = 0, allocated = 0; const char *c; assert(p); assert(*p); assert(ret); c = *p; if (*c != '"') return -EINVAL; c++; for (;;) { int len; /* Check for EOF */ if (*c == 0) return -EINVAL; /* Check for control characters 0x00..0x1f */ if (*c > 0 && *c < ' ') return -EINVAL; /* Check for control character 0x7f */ if (*c == 0x7f) return -EINVAL; if (*c == '"') { if (!s) { s = strdup(""); if (!s) return -ENOMEM; } else s[n] = 0; *p = c + 1; *ret = s; s = NULL; return JSON_STRING; } if (*c == '\\') { char ch = 0; c++; if (*c == 0) return -EINVAL; if (IN_SET(*c, '"', '\\', '/')) ch = *c; else if (*c == 'b') ch = '\b'; else if (*c == 'f') ch = '\f'; else if (*c == 'n') ch = '\n'; else if (*c == 'r') ch = '\r'; else if (*c == 't') ch = '\t'; else if (*c == 'u') { uint16_t x; int r; r = unhex_ucs2(c + 1, &x); if (r < 0) return r; c += 5; if (!GREEDY_REALLOC(s, allocated, n + 4)) return -ENOMEM; if (!utf16_is_surrogate(x)) n += utf8_encode_unichar(s + n, x); else if (utf16_is_trailing_surrogate(x)) return -EINVAL; else { uint16_t y; if (c[0] != '\\' || c[1] != 'u') return -EINVAL; r = unhex_ucs2(c + 2, &y); if (r < 0) return r; c += 6; if (!utf16_is_trailing_surrogate(y)) return -EINVAL; n += utf8_encode_unichar(s + n, utf16_surrogate_pair_to_unichar(x, y)); } continue; } else return -EINVAL; if (!GREEDY_REALLOC(s, allocated, n + 2)) return -ENOMEM; s[n++] = ch; c ++; continue; } len = utf8_encoded_valid_unichar(c); if (len < 0) return len; if (!GREEDY_REALLOC(s, allocated, n + len + 1)) return -ENOMEM; memcpy(s + n, c, len); n += len; c += len; } }
static int json_scoped_parse(JsonVariant **tokens, size_t *i, size_t n, JsonVariant *scope) { bool arr = scope->type == JSON_VARIANT_ARRAY; int terminator = arr ? JSON_ARRAY_CLOSE : JSON_OBJECT_CLOSE; size_t allocated = 0, size = 0; JsonVariant *key = NULL, *value = NULL, *var = NULL, *items = NULL; enum { STATE_KEY, STATE_COLON, STATE_COMMA, STATE_VALUE } state = arr ? STATE_VALUE : STATE_KEY; assert(tokens); assert(i); assert(scope); while((var = *i < n ? tokens[(*i)++] : NULL) != NULL) { bool stopper; int r; stopper = !json_is_value(var) && var->value.integer == terminator; if (stopper) { if (state != STATE_COMMA && size > 0) goto error; goto out; } if (state == STATE_KEY) { if (var->type != JSON_VARIANT_STRING) goto error; else { key = var; state = STATE_COLON; } } else if (state == STATE_COLON) { if (key == NULL) goto error; if (json_is_value(var)) goto error; if (var->value.integer != JSON_COLON) goto error; state = STATE_VALUE; } else if (state == STATE_VALUE) { _cleanup_json_variant_unref_ JsonVariant *v = NULL; size_t toadd = arr ? 1 : 2; if (!json_is_value(var)) { int type = (var->value.integer == JSON_ARRAY_OPEN) ? JSON_VARIANT_ARRAY : JSON_VARIANT_OBJECT; r = json_variant_new(&v, type); if (r < 0) goto error; r = json_scoped_parse(tokens, i, n, v); if (r < 0) goto error; value = v; } else value = var; if(!GREEDY_REALLOC(items, allocated, size + toadd)) goto error; if (arr) { r = json_variant_deep_copy(&items[size], value); if (r < 0) goto error; } else { r = json_variant_deep_copy(&items[size], key); if (r < 0) goto error; r = json_variant_deep_copy(&items[size+1], value); if (r < 0) goto error; } size += toadd; state = STATE_COMMA; } else if (state == STATE_COMMA) { if (json_is_value(var)) goto error; if (var->value.integer != JSON_COMMA) goto error; key = NULL; value = NULL; state = arr ? STATE_VALUE : STATE_KEY; } } error: json_raw_unref(items, size); return -EBADMSG; out: scope->size = size; scope->objects = items; return scope->type; }
int journal_directory_vacuum( const char *directory, uint64_t max_use, usec_t max_retention_usec, usec_t *oldest_usec) { _cleanup_closedir_ DIR *d = NULL; int r = 0; struct vacuum_info *list = NULL; unsigned n_list = 0, i; size_t n_allocated = 0; uint64_t sum = 0, freed = 0; usec_t retention_limit = 0; assert(directory); if (max_use <= 0 && max_retention_usec <= 0) return 0; if (max_retention_usec > 0) { retention_limit = now(CLOCK_REALTIME); if (retention_limit > max_retention_usec) retention_limit -= max_retention_usec; else max_retention_usec = retention_limit = 0; } d = opendir(directory); if (!d) return -errno; for (;;) { struct dirent *de; size_t q; struct stat st; char *p; unsigned long long seqnum = 0, realtime; sd_id128_t seqnum_id; bool have_seqnum; errno = 0; de = readdir(d); if (!de && errno != 0) { r = -errno; goto finish; } if (!de) break; if (fstatat(dirfd(d), de->d_name, &st, AT_SYMLINK_NOFOLLOW) < 0) continue; if (!S_ISREG(st.st_mode)) continue; q = strlen(de->d_name); if (endswith(de->d_name, ".journal")) { /* Vacuum archived files */ if (q < 1 + 32 + 1 + 16 + 1 + 16 + 8) continue; if (de->d_name[q-8-16-1] != '-' || de->d_name[q-8-16-1-16-1] != '-' || de->d_name[q-8-16-1-16-1-32-1] != '@') continue; p = strdup(de->d_name); if (!p) { r = -ENOMEM; goto finish; } de->d_name[q-8-16-1-16-1] = 0; if (sd_id128_from_string(de->d_name + q-8-16-1-16-1-32, &seqnum_id) < 0) { free(p); continue; } if (sscanf(de->d_name + q-8-16-1-16, "%16llx-%16llx.journal", &seqnum, &realtime) != 2) { free(p); continue; } have_seqnum = true; } else if (endswith(de->d_name, ".journal~")) { unsigned long long tmp; /* Vacuum corrupted files */ if (q < 1 + 16 + 1 + 16 + 8 + 1) continue; if (de->d_name[q-1-8-16-1] != '-' || de->d_name[q-1-8-16-1-16-1] != '@') continue; p = strdup(de->d_name); if (!p) { r = -ENOMEM; goto finish; } if (sscanf(de->d_name + q-1-8-16-1-16, "%16llx-%16llx.journal~", &realtime, &tmp) != 2) { free(p); continue; } have_seqnum = false; } else /* We do not vacuum active files or unknown files! */ continue; if (journal_file_empty(dirfd(d), p)) { /* Always vacuum empty non-online files. */ uint64_t size = 512UL * (uint64_t) st.st_blocks; if (unlinkat(dirfd(d), p, 0) >= 0) { log_info("Deleted empty journal %s/%s (%"PRIu64" bytes).", directory, p, size); freed += size; } else if (errno != ENOENT) log_warning("Failed to delete %s/%s: %m", directory, p); free(p); continue; } patch_realtime(directory, p, &st, &realtime); GREEDY_REALLOC(list, n_allocated, n_list + 1); list[n_list].filename = p; list[n_list].usage = 512UL * (uint64_t) st.st_blocks; list[n_list].seqnum = seqnum; list[n_list].realtime = realtime; list[n_list].seqnum_id = seqnum_id; list[n_list].have_seqnum = have_seqnum; sum += list[n_list].usage; n_list ++; } qsort_safe(list, n_list, sizeof(struct vacuum_info), vacuum_compare); for (i = 0; i < n_list; i++) { if ((max_retention_usec <= 0 || list[i].realtime >= retention_limit) && (max_use <= 0 || sum <= max_use)) break; if (unlinkat(dirfd(d), list[i].filename, 0) >= 0) { log_debug("Deleted archived journal %s/%s (%"PRIu64" bytes).", directory, list[i].filename, list[i].usage); freed += list[i].usage; if (list[i].usage < sum) sum -= list[i].usage; else sum = 0; } else if (errno != ENOENT) log_warning("Failed to delete %s/%s: %m", directory, list[i].filename); } if (oldest_usec && i < n_list && (*oldest_usec == 0 || list[i].realtime < *oldest_usec)) *oldest_usec = list[i].realtime; finish: for (i = 0; i < n_list; i++) free(list[i].filename); free(list); log_debug("Vacuuming done, freed %"PRIu64" bytes", freed); return r; }
static int acquire_time_data(sd_bus *bus, struct unit_times **out) { _cleanup_bus_message_unref_ sd_bus_message *reply = NULL; _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL; int r, c = 0; struct unit_times *unit_times = NULL; size_t size = 0; UnitInfo u; r = sd_bus_call_method( bus, "org.freedesktop.systemd1", "/org/freedesktop/systemd1", "org.freedesktop.systemd1.Manager", "ListUnits", &error, &reply, NULL); if (r < 0) { log_error("Failed to list units: %s", bus_error_message(&error, -r)); goto fail; } r = sd_bus_message_enter_container(reply, SD_BUS_TYPE_ARRAY, "(ssssssouso)"); if (r < 0) { bus_log_parse_error(r); goto fail; } while ((r = bus_parse_unit_info(reply, &u)) > 0) { struct unit_times *t; if (!GREEDY_REALLOC(unit_times, size, c+1)) { r = log_oom(); goto fail; } t = unit_times+c; t->name = NULL; assert_cc(sizeof(usec_t) == sizeof(uint64_t)); if (bus_get_uint64_property(bus, u.unit_path, "org.freedesktop.systemd1.Unit", "InactiveExitTimestampMonotonic", &t->activating) < 0 || bus_get_uint64_property(bus, u.unit_path, "org.freedesktop.systemd1.Unit", "ActiveEnterTimestampMonotonic", &t->activated) < 0 || bus_get_uint64_property(bus, u.unit_path, "org.freedesktop.systemd1.Unit", "ActiveExitTimestampMonotonic", &t->deactivating) < 0 || bus_get_uint64_property(bus, u.unit_path, "org.freedesktop.systemd1.Unit", "InactiveEnterTimestampMonotonic", &t->deactivated) < 0) { r = -EIO; goto fail; } if (t->activated >= t->activating) t->time = t->activated - t->activating; else if (t->deactivated >= t->activating) t->time = t->deactivated - t->activating; else t->time = 0; if (t->activating == 0) continue; t->name = strdup(u.id); if (t->name == NULL) { r = log_oom(); goto fail; } c++; } if (r < 0) { bus_log_parse_error(r); goto fail; } *out = unit_times; return c; fail: free_unit_times(unit_times, (unsigned) c); return r; }
static int parse_ancestry(const void *payload, size_t size, char ***ret) { _cleanup_free_ char *buf = NULL; void *json_state = NULL; const char *p; enum { STATE_BEGIN, STATE_ITEM, STATE_COMMA, STATE_END, } state = STATE_BEGIN; _cleanup_strv_free_ char **l = NULL; size_t n = 0, allocated = 0; if (size <= 0) return -EBADMSG; if (memchr(payload, 0, size)) return -EBADMSG; buf = strndup(payload, size); if (!buf) return -ENOMEM; p = buf; for (;;) { _cleanup_free_ char *str; union json_value v = {}; int t; t = json_tokenize(&p, &str, &v, &json_state, NULL); if (t < 0) return t; switch (state) { case STATE_BEGIN: if (t == JSON_ARRAY_OPEN) state = STATE_ITEM; else return -EBADMSG; break; case STATE_ITEM: if (t == JSON_STRING) { if (!dkr_id_is_valid(str)) return -EBADMSG; if (n+1 > LAYERS_MAX) return -EFBIG; if (!GREEDY_REALLOC(l, allocated, n + 2)) return -ENOMEM; l[n++] = str; str = NULL; l[n] = NULL; state = STATE_COMMA; } else if (t == JSON_ARRAY_CLOSE) state = STATE_END; else return -EBADMSG; break; case STATE_COMMA: if (t == JSON_COMMA) state = STATE_ITEM; else if (t == JSON_ARRAY_CLOSE) state = STATE_END; else return -EBADMSG; break; case STATE_END: if (t == JSON_END) { if (strv_isempty(l)) return -EBADMSG; if (!strv_is_uniq(l)) return -EBADMSG; l = strv_reverse(l); *ret = l; l = NULL; return 0; } else return -EBADMSG; } } }
int change_uid_gid(const char *user, char **_home) { char line[LINE_MAX], *x, *u, *g, *h; const char *word, *state; _cleanup_free_ uid_t *uids = NULL; _cleanup_free_ char *home = NULL; _cleanup_fclose_ FILE *f = NULL; _cleanup_close_ int fd = -1; unsigned n_uids = 0; size_t sz = 0, l; uid_t uid; gid_t gid; pid_t pid; int r; assert(_home); if (!user || streq(user, "root") || streq(user, "0")) { /* Reset everything fully to 0, just in case */ r = reset_uid_gid(); if (r < 0) return log_error_errno(r, "Failed to become root: %m"); *_home = NULL; return 0; } /* First, get user credentials */ fd = spawn_getent("passwd", user, &pid); if (fd < 0) return fd; f = fdopen(fd, "r"); if (!f) return log_oom(); fd = -1; if (!fgets(line, sizeof(line), f)) { if (!ferror(f)) { log_error("Failed to resolve user %s.", user); return -ESRCH; } log_error_errno(errno, "Failed to read from getent: %m"); return -errno; } truncate_nl(line); wait_for_terminate_and_warn("getent passwd", pid, true); x = strchr(line, ':'); if (!x) { log_error("/etc/passwd entry has invalid user field."); return -EIO; } u = strchr(x+1, ':'); if (!u) { log_error("/etc/passwd entry has invalid password field."); return -EIO; } u++; g = strchr(u, ':'); if (!g) { log_error("/etc/passwd entry has invalid UID field."); return -EIO; } *g = 0; g++; x = strchr(g, ':'); if (!x) { log_error("/etc/passwd entry has invalid GID field."); return -EIO; } *x = 0; h = strchr(x+1, ':'); if (!h) { log_error("/etc/passwd entry has invalid GECOS field."); return -EIO; } h++; x = strchr(h, ':'); if (!x) { log_error("/etc/passwd entry has invalid home directory field."); return -EIO; } *x = 0; r = parse_uid(u, &uid); if (r < 0) { log_error("Failed to parse UID of user."); return -EIO; } r = parse_gid(g, &gid); if (r < 0) { log_error("Failed to parse GID of user."); return -EIO; } home = strdup(h); if (!home) return log_oom(); /* Second, get group memberships */ fd = spawn_getent("initgroups", user, &pid); if (fd < 0) return fd; fclose(f); f = fdopen(fd, "r"); if (!f) return log_oom(); fd = -1; if (!fgets(line, sizeof(line), f)) { if (!ferror(f)) { log_error("Failed to resolve user %s.", user); return -ESRCH; } log_error_errno(errno, "Failed to read from getent: %m"); return -errno; } truncate_nl(line); wait_for_terminate_and_warn("getent initgroups", pid, true); /* Skip over the username and subsequent separator whitespace */ x = line; x += strcspn(x, WHITESPACE); x += strspn(x, WHITESPACE); FOREACH_WORD(word, l, x, state) { char c[l+1]; memcpy(c, word, l); c[l] = 0; if (!GREEDY_REALLOC(uids, sz, n_uids+1)) return log_oom(); r = parse_uid(c, &uids[n_uids++]); if (r < 0) { log_error("Failed to parse group data from getent."); return -EIO; } }
void server_process_native_message( Server *s, const void *buffer, size_t buffer_size, const struct ucred *ucred, const struct timeval *tv, const char *label, size_t label_len) { struct iovec *iovec = NULL; unsigned n = 0, j, tn = (unsigned) -1; const char *p; size_t remaining, m = 0, entry_size = 0; int priority = LOG_INFO; char *identifier = NULL, *message = NULL; pid_t object_pid = 0; assert(s); assert(buffer || buffer_size == 0); p = buffer; remaining = buffer_size; while (remaining > 0) { const char *e, *q; e = memchr(p, '\n', remaining); if (!e) { /* Trailing noise, let's ignore it, and flush what we collected */ log_debug("Received message with trailing noise, ignoring."); break; } if (e == p) { /* Entry separator */ if (entry_size + n + 1 > ENTRY_SIZE_MAX) { /* data + separators + trailer */ log_debug("Entry is too big with %u properties and %zu bytes, ignoring.", n, entry_size); continue; } server_dispatch_message(s, iovec, n, m, ucred, tv, label, label_len, NULL, priority, object_pid); n = 0; priority = LOG_INFO; entry_size = 0; p++; remaining--; continue; } if (*p == '.' || *p == '#') { /* Ignore control commands for now, and * comments too. */ remaining -= (e - p) + 1; p = e + 1; continue; } /* A property follows */ /* n existing properties, 1 new, +1 for _TRANSPORT */ if (!GREEDY_REALLOC(iovec, m, n + 2 + N_IOVEC_META_FIELDS + N_IOVEC_OBJECT_FIELDS)) { log_oom(); break; } q = memchr(p, '=', e - p); if (q) { if (valid_user_field(p, q - p, false)) { size_t l; l = e - p; /* If the field name starts with an * underscore, skip the variable, * since that indidates a trusted * field */ iovec[n].iov_base = (char*) p; iovec[n].iov_len = l; entry_size += iovec[n].iov_len; n++; /* We need to determine the priority * of this entry for the rate limiting * logic */ if (l == 10 && startswith(p, "PRIORITY=") && p[9] >= '0' && p[9] <= '9') priority = (priority & LOG_FACMASK) | (p[9] - '0'); else if (l == 17 && startswith(p, "SYSLOG_FACILITY=") && p[16] >= '0' && p[16] <= '9') priority = (priority & LOG_PRIMASK) | ((p[16] - '0') << 3); else if (l == 18 && startswith(p, "SYSLOG_FACILITY=") && p[16] >= '0' && p[16] <= '9' && p[17] >= '0' && p[17] <= '9') priority = (priority & LOG_PRIMASK) | (((p[16] - '0')*10 + (p[17] - '0')) << 3); else if (l >= 19 && startswith(p, "SYSLOG_IDENTIFIER=")) { char *t; t = strndup(p + 18, l - 18); if (t) { free(identifier); identifier = t; } } else if (l >= 8 && startswith(p, "MESSAGE=")) { char *t; t = strndup(p + 8, l - 8); if (t) { free(message); message = t; } } else if (l > strlen("OBJECT_PID=") && l < strlen("OBJECT_PID=") + DECIMAL_STR_MAX(pid_t) && startswith(p, "OBJECT_PID=") && allow_object_pid(ucred)) { char buf[DECIMAL_STR_MAX(pid_t)]; memcpy(buf, p + strlen("OBJECT_PID="), l - strlen("OBJECT_PID=")); buf[l-strlen("OBJECT_PID=")] = '\0'; /* ignore error */ parse_pid(buf, &object_pid); } } remaining -= (e - p) + 1; p = e + 1; continue; } else { le64_t l_le; uint64_t l; char *k; if (remaining < e - p + 1 + sizeof(uint64_t) + 1) { log_debug("Failed to parse message, ignoring."); break; } memcpy(&l_le, e + 1, sizeof(uint64_t)); l = le64toh(l_le); if (l > DATA_SIZE_MAX) { log_debug("Received binary data block of %"PRIu64" bytes is too large, ignoring.", l); break; } if ((uint64_t) remaining < e - p + 1 + sizeof(uint64_t) + l + 1 || e[1+sizeof(uint64_t)+l] != '\n') { log_debug("Failed to parse message, ignoring."); break; } k = malloc((e - p) + 1 + l); if (!k) { log_oom(); break; } memcpy(k, p, e - p); k[e - p] = '='; memcpy(k + (e - p) + 1, e + 1 + sizeof(uint64_t), l); if (valid_user_field(p, e - p, false)) { iovec[n].iov_base = k; iovec[n].iov_len = (e - p) + 1 + l; entry_size += iovec[n].iov_len; n++; } else free(k); remaining -= (e - p) + 1 + sizeof(uint64_t) + l + 1; p = e + 1 + sizeof(uint64_t) + l + 1; } } if (n <= 0) goto finish; tn = n++; IOVEC_SET_STRING(iovec[tn], "_TRANSPORT=journal"); entry_size += strlen("_TRANSPORT=journal"); if (entry_size + n + 1 > ENTRY_SIZE_MAX) { /* data + separators + trailer */ log_debug("Entry is too big with %u properties and %zu bytes, ignoring.", n, entry_size); goto finish; } if (message) { if (s->forward_to_syslog) server_forward_syslog(s, priority, identifier, message, ucred, tv); if (s->forward_to_kmsg) server_forward_kmsg(s, priority, identifier, message, ucred); if (s->forward_to_console) server_forward_console(s, priority, identifier, message, ucred); if (s->forward_to_wall) server_forward_wall(s, priority, identifier, message, ucred); } server_dispatch_message(s, iovec, n, m, ucred, tv, label, label_len, NULL, priority, object_pid); finish: for (j = 0; j < n; j++) { if (j == tn) continue; if (iovec[j].iov_base < buffer || (const uint8_t*) iovec[j].iov_base >= (const uint8_t*) buffer + buffer_size) free(iovec[j].iov_base); } free(iovec); free(identifier); free(message); }