diff options
| author | Michael Biebl <biebl@debian.org> | 2017-01-17 20:25:09 +0100 |
|---|---|---|
| committer | Michael Biebl <biebl@debian.org> | 2017-01-17 20:25:09 +0100 |
| commit | 58f8be580039b0575b197b9573a1c92745d96d30 (patch) | |
| tree | 2c226233f623a0dcb529be0eb8cdf97e4a2ae0c0 /src/systemd | |
| parent | 45cb5bb3c0e6edb887cf69b417fcaf7053814a9b (diff) | |
New upstream version 1.5.90 upstream/1.5.90
Diffstat (limited to 'src/systemd')
52 files changed, 905 insertions, 264 deletions
diff --git a/src/systemd/nm-sd.h b/src/systemd/nm-sd.h index f07a7082..f988dfd0 100644 --- a/src/systemd/nm-sd.h +++ b/src/systemd/nm-sd.h @@ -19,6 +19,13 @@ #ifndef __NM_SD_H__ #define __NM_SD_H__ +#include "systemd/src/systemd/sd-dhcp-client.h" +#include "systemd/src/systemd/sd-dhcp6-client.h" +#include "systemd/src/systemd/sd-lldp.h" +#include "systemd/src/systemd/sd-ipv4ll.h" + +/*****************************************************************************/ + guint nm_sd_event_attach_default (void); /***************************************************************************** diff --git a/src/systemd/sd-adapt/formats-util.h b/src/systemd/sd-adapt/format-util.h index 637892c2..637892c2 100644 --- a/src/systemd/sd-adapt/formats-util.h +++ b/src/systemd/sd-adapt/format-util.h diff --git a/src/systemd/sd-adapt/glob-util.h b/src/systemd/sd-adapt/glob-util.h new file mode 100644 index 00000000..637892c2 --- /dev/null +++ b/src/systemd/sd-adapt/glob-util.h @@ -0,0 +1,3 @@ +#pragma once + +/* dummy header */ diff --git a/src/systemd/sd-adapt/khash.h b/src/systemd/sd-adapt/khash.h new file mode 100644 index 00000000..637892c2 --- /dev/null +++ b/src/systemd/sd-adapt/khash.h @@ -0,0 +1,3 @@ +#pragma once + +/* dummy header */ diff --git a/src/systemd/src/basic/alloc-util.h b/src/systemd/src/basic/alloc-util.h index ceeee519..a44dd473 100644 --- a/src/systemd/src/basic/alloc-util.h +++ b/src/systemd/src/basic/alloc-util.h @@ -43,6 +43,14 @@ static inline void *mfree(void *memory) { return NULL; } +#define free_and_replace(a, b) \ + ({ \ + free(a); \ + (a) = (b); \ + (b) = NULL; \ + 0; \ + }) + void* memdup(const void *p, size_t l) _alloc_(2); static inline void freep(void *p) { diff --git a/src/systemd/src/basic/escape.c b/src/systemd/src/basic/escape.c index 406b791f..ac96f0ee 100644 --- a/src/systemd/src/basic/escape.c +++ b/src/systemd/src/basic/escape.c @@ -335,7 +335,7 @@ int cunescape_length_with_prefix(const char *s, size_t length, const char *prefi assert(remaining > 0); if (*f != '\\') { - /* A literal literal, copy verbatim */ + /* A literal, copy verbatim */ *(t++) = *f; continue; } diff --git a/src/systemd/src/basic/extract-word.c b/src/systemd/src/basic/extract-word.c index eb54daa3..734712dc 100644 --- a/src/systemd/src/basic/extract-word.c +++ b/src/systemd/src/basic/extract-word.c @@ -50,7 +50,7 @@ int extract_first_word(const char **p, char **ret, const char *separators, Extra /* Bail early if called after last value or with no input */ if (!*p) - goto finish_force_terminate; + goto finish; c = **p; if (!separators) @@ -230,8 +230,8 @@ int extract_first_word_and_warn( *p = save; r = extract_first_word(p, ret, separators, flags|EXTRACT_CUNESCAPE_RELAX); if (r >= 0) { - /* It worked this time, hence it must have been an invalid escape sequence we could correct. */ - log_syntax(unit, LOG_WARNING, filename, line, EINVAL, "Invalid escape sequences in line, correcting: \"%s\"", rvalue); + /* It worked this time, hence it must have been an invalid escape sequence. */ + log_syntax(unit, LOG_WARNING, filename, line, EINVAL, "Ignoring unknown escape sequences: \"%s\"", *ret); return r; } diff --git a/src/systemd/src/basic/fd-util.c b/src/systemd/src/basic/fd-util.c index c518f757..d1c988e1 100644 --- a/src/systemd/src/basic/fd-util.c +++ b/src/systemd/src/basic/fd-util.c @@ -26,6 +26,7 @@ #include <sys/stat.h> #include <unistd.h> +#include "dirent-util.h" #include "fd-util.h" #include "fs-util.h" #include "macro.h" @@ -237,12 +238,9 @@ int close_all_fds(const int except[], unsigned n_except) { return r; } - while ((de = readdir(d))) { + FOREACH_DIRENT(de, d, return -errno) { int fd = -1; - if (hidden_or_backup_file(de->d_name)) - continue; - if (safe_atoi(de->d_name, &fd) < 0) /* Let's better ignore this, just in case */ continue; diff --git a/src/systemd/src/basic/fileio.c b/src/systemd/src/basic/fileio.c index b2fe15ca..8ef0db7f 100644 --- a/src/systemd/src/basic/fileio.c +++ b/src/systemd/src/basic/fileio.c @@ -39,6 +39,7 @@ #include "hexdecoct.h" #include "log.h" #include "macro.h" +#include "missing.h" #include "parse-util.h" #include "path-util.h" #include "random-util.h" @@ -677,7 +678,7 @@ static int load_env_file_push( return -EINVAL; } - p = strjoin(key, "=", strempty(value), NULL); + p = strjoin(key, "=", strempty(value)); if (!p) return -ENOMEM; @@ -965,9 +966,9 @@ static int search_and_fopen_internal(const char *path, const char *mode, const c FILE *f; if (root) - p = strjoin(root, *i, "/", path, NULL); + p = strjoin(root, *i, "/", path); else - p = strjoin(*i, "/", path, NULL); + p = strjoin(*i, "/", path); if (!p) return -ENOMEM; @@ -1046,7 +1047,7 @@ int fopen_temporary(const char *path, FILE **_f, char **_temp_path) { if (r < 0) return r; - fd = mkostemp_safe(t, O_WRONLY|O_CLOEXEC); + fd = mkostemp_safe(t); if (fd < 0) { free(t); return -errno; @@ -1079,7 +1080,7 @@ int fflush_and_check(FILE *f) { } /* This is much like mkostemp() but is subject to umask(). */ -int mkostemp_safe(char *pattern, int flags) { +int mkostemp_safe(char *pattern) { _cleanup_umask_ mode_t u = 0; int fd; @@ -1087,7 +1088,7 @@ int mkostemp_safe(char *pattern, int flags) { u = umask(077); - fd = mkostemp(pattern, flags); + fd = mkostemp(pattern, O_CLOEXEC); if (fd < 0) return -errno; @@ -1287,17 +1288,15 @@ int open_tmpfile_unlinkable(const char *directory, int flags) { /* Returns an unlinked temporary file that cannot be linked into the file system anymore */ -#ifdef O_TMPFILE /* Try O_TMPFILE first, if it is supported */ fd = open(directory, flags|O_TMPFILE|O_EXCL, S_IRUSR|S_IWUSR); if (fd >= 0) return fd; -#endif /* Fall back to unguessable name + unlinking */ p = strjoina(directory, "/systemd-tmp-XXXXXX"); - fd = mkostemp_safe(p, flags); + fd = mkostemp_safe(p); if (fd < 0) return fd; @@ -1320,7 +1319,6 @@ int open_tmpfile_linkable(const char *target, int flags, char **ret_path) { * which case "ret_path" will be returned as NULL. If not possible a the tempoary path name used is returned in * "ret_path". Use link_tmpfile() below to rename the result after writing the file in full. */ -#ifdef O_TMPFILE { _cleanup_free_ char *dn = NULL; @@ -1336,7 +1334,6 @@ int open_tmpfile_linkable(const char *target, int flags, char **ret_path) { log_debug_errno(errno, "Failed to use O_TMPFILE on %s: %m", dn); } -#endif r = tempfn_random(target, NULL, &tmp); if (r < 0) @@ -1419,4 +1416,23 @@ int read_nul_string(FILE *f, char **ret) { return 0; } + +int mkdtemp_malloc(const char *template, char **ret) { + char *p; + + assert(template); + assert(ret); + + p = strdup(template); + if (!p) + return -ENOMEM; + + if (!mkdtemp(p)) { + free(p); + return -errno; + } + + *ret = p; + return 0; +} #endif /* NM_IGNORED */ diff --git a/src/systemd/src/basic/fileio.h b/src/systemd/src/basic/fileio.h index 9ac497d9..17b38a5d 100644 --- a/src/systemd/src/basic/fileio.h +++ b/src/systemd/src/basic/fileio.h @@ -71,7 +71,7 @@ int search_and_fopen_nulstr(const char *path, const char *mode, const char *root int fflush_and_check(FILE *f); int fopen_temporary(const char *path, FILE **_f, char **_temp_path); -int mkostemp_safe(char *pattern, int flags); +int mkostemp_safe(char *pattern); int tempfn_xxxxxx(const char *p, const char *extra, char **ret); int tempfn_random(const char *p, const char *extra, char **ret); @@ -88,3 +88,5 @@ int open_tmpfile_linkable(const char *target, int flags, char **ret_path); int link_tmpfile(int fd, const char *path, const char *target); int read_nul_string(FILE *f, char **ret); + +int mkdtemp_malloc(const char *template, char **ret); diff --git a/src/systemd/src/basic/fs-util.c b/src/systemd/src/basic/fs-util.c index de0cd8fb..3919fbcd 100644 --- a/src/systemd/src/basic/fs-util.c +++ b/src/systemd/src/basic/fs-util.c @@ -19,7 +19,6 @@ #include "nm-sd-adapt.h" -#include <dirent.h> #include <errno.h> #include <stddef.h> #include <stdio.h> @@ -229,25 +228,25 @@ int readlink_and_make_absolute(const char *p, char **r) { return 0; } -int readlink_and_canonicalize(const char *p, char **r) { +int readlink_and_canonicalize(const char *p, const char *root, char **ret) { char *t, *s; - int j; + int r; assert(p); - assert(r); + assert(ret); - j = readlink_and_make_absolute(p, &t); - if (j < 0) - return j; + r = readlink_and_make_absolute(p, &t); + if (r < 0) + return r; - s = canonicalize_file_name(t); - if (s) { + r = chase_symlinks(t, root, 0, &s); + if (r < 0) + /* If we can't follow up, then let's return the original string, slightly cleaned up. */ + *ret = path_kill_slashes(t); + else { + *ret = s; free(t); - *r = s; - } else - *r = t; - - path_kill_slashes(*r); + } return 0; } @@ -453,6 +452,7 @@ int mkfifo_atomic(const char *path, mode_t mode) { int get_files_in_directory(const char *path, char ***list) { _cleanup_closedir_ DIR *d = NULL; + struct dirent *de; size_t bufsize = 0, n = 0; _cleanup_strv_free_ char **l = NULL; @@ -466,16 +466,7 @@ int get_files_in_directory(const char *path, char ***list) { if (!d) return -errno; - for (;;) { - struct dirent *de; - - errno = 0; - de = readdir(d); - if (!de && errno > 0) - return -errno; - if (!de) - break; - + FOREACH_DIRENT_ALL(de, d, return -errno) { dirent_ensure_type(d, de); if (!dirent_is_file(de)) @@ -604,4 +595,220 @@ int inotify_add_watch_fd(int fd, int what, uint32_t mask) { return r; } + +int chase_symlinks(const char *path, const char *original_root, unsigned flags, char **ret) { + _cleanup_free_ char *buffer = NULL, *done = NULL, *root = NULL; + _cleanup_close_ int fd = -1; + unsigned max_follow = 32; /* how many symlinks to follow before giving up and returning ELOOP */ + bool exists = true; + char *todo; + int r; + + assert(path); + + /* This is a lot like canonicalize_file_name(), but takes an additional "root" parameter, that allows following + * symlinks relative to a root directory, instead of the root of the host. + * + * Note that "root" primarily matters if we encounter an absolute symlink. It is also used when following + * relative symlinks to ensure they cannot be used to "escape" the root directory. The path parameter passed is + * assumed to be already prefixed by it, except if the CHASE_PREFIX_ROOT flag is set, in which case it is first + * prefixed accordingly. + * + * Algorithmically this operates on two path buffers: "done" are the components of the path we already + * processed and resolved symlinks, "." and ".." of. "todo" are the components of the path we still need to + * process. On each iteration, we move one component from "todo" to "done", processing it's special meaning + * each time. The "todo" path always starts with at least one slash, the "done" path always ends in no + * slash. We always keep an O_PATH fd to the component we are currently processing, thus keeping lookup races + * at a minimum. + * + * Suggested usage: whenever you want to canonicalize a path, use this function. Pass the absolute path you got + * as-is: fully qualified and relative to your host's root. Optionally, specify the root parameter to tell this + * function what to do when encountering a symlink with an absolute path as directory: prefix it by the + * specified path. + * + * Note: there's also chase_symlinks_prefix() (see below), which as first step prefixes the passed path by the + * passed root. */ + + if (original_root) { + r = path_make_absolute_cwd(original_root, &root); + if (r < 0) + return r; + + if (flags & CHASE_PREFIX_ROOT) + path = prefix_roota(root, path); + } + + r = path_make_absolute_cwd(path, &buffer); + if (r < 0) + return r; + + fd = open("/", O_CLOEXEC|O_NOFOLLOW|O_PATH); + if (fd < 0) + return -errno; + + todo = buffer; + for (;;) { + _cleanup_free_ char *first = NULL; + _cleanup_close_ int child = -1; + struct stat st; + size_t n, m; + + /* Determine length of first component in the path */ + n = strspn(todo, "/"); /* The slashes */ + m = n + strcspn(todo + n, "/"); /* The entire length of the component */ + + /* Extract the first component. */ + first = strndup(todo, m); + if (!first) + return -ENOMEM; + + todo += m; + + /* Just a single slash? Then we reached the end. */ + if (isempty(first) || path_equal(first, "/")) + break; + + /* Just a dot? Then let's eat this up. */ + if (path_equal(first, "/.")) + continue; + + /* Two dots? Then chop off the last bit of what we already found out. */ + if (path_equal(first, "/..")) { + _cleanup_free_ char *parent = NULL; + int fd_parent = -1; + + /* If we already are at the top, then going up will not change anything. This is in-line with + * how the kernel handles this. */ + if (isempty(done) || path_equal(done, "/")) + continue; + + parent = dirname_malloc(done); + if (!parent) + return -ENOMEM; + + /* Don't allow this to leave the root dir. */ + if (root && + path_startswith(done, root) && + !path_startswith(parent, root)) + continue; + + free_and_replace(done, parent); + + fd_parent = openat(fd, "..", O_CLOEXEC|O_NOFOLLOW|O_PATH); + if (fd_parent < 0) + return -errno; + + safe_close(fd); + fd = fd_parent; + + continue; + } + + /* Otherwise let's see what this is. */ + child = openat(fd, first + n, O_CLOEXEC|O_NOFOLLOW|O_PATH); + if (child < 0) { + + if (errno == ENOENT && + (flags & CHASE_NONEXISTENT) && + (isempty(todo) || path_is_safe(todo))) { + + /* If CHASE_NONEXISTENT is set, and the path does not exist, then that's OK, return + * what we got so far. But don't allow this if the remaining path contains "../ or "./" + * or something else weird. */ + + if (!strextend(&done, first, todo, NULL)) + return -ENOMEM; + + exists = false; + break; + } + + return -errno; + } + + if (fstat(child, &st) < 0) + return -errno; + + if (S_ISLNK(st.st_mode)) { + _cleanup_free_ char *destination = NULL; + + /* This is a symlink, in this case read the destination. But let's make sure we don't follow + * symlinks without bounds. */ + if (--max_follow <= 0) + return -ELOOP; + + r = readlinkat_malloc(fd, first + n, &destination); + if (r < 0) + return r; + if (isempty(destination)) + return -EINVAL; + + if (path_is_absolute(destination)) { + + /* An absolute destination. Start the loop from the beginning, but use the root + * directory as base. */ + + safe_close(fd); + fd = open(root ?: "/", O_CLOEXEC|O_NOFOLLOW|O_PATH); + if (fd < 0) + return -errno; + + free_and_replace(buffer, destination); + + todo = buffer; + free(done); + + /* Note that we do not revalidate the root, we take it as is. */ + if (isempty(root)) + done = NULL; + else { + done = strdup(root); + if (!done) + return -ENOMEM; + } + + } else { + char *joined; + + /* A relative destination. If so, this is what we'll prefix what's left to do with what + * we just read, and start the loop again, but remain in the current directory. */ + + joined = strjoin("/", destination, todo); + if (!joined) + return -ENOMEM; + + free(buffer); + todo = buffer = joined; + } + + continue; + } + + /* If this is not a symlink, then let's just add the name we read to what we already verified. */ + if (!done) { + done = first; + first = NULL; + } else { + if (!strextend(&done, first, NULL)) + return -ENOMEM; + } + + /* And iterate again, but go one directory further down. */ + safe_close(fd); + fd = child; + child = -1; + } + + if (!done) { + /* Special case, turn the empty string into "/", to indicate the root directory. */ + done = strdup("/"); + if (!done) + return -ENOMEM; + } + + *ret = done; + done = NULL; + + return exists; +} #endif /* NM_IGNORED */ diff --git a/src/systemd/src/basic/fs-util.h b/src/systemd/src/basic/fs-util.h index 2c3b9a1c..5fe5c71f 100644 --- a/src/systemd/src/basic/fs-util.h +++ b/src/systemd/src/basic/fs-util.h @@ -39,7 +39,7 @@ int readlinkat_malloc(int fd, const char *p, char **ret); int readlink_malloc(const char *p, char **r); int readlink_value(const char *p, char **ret); int readlink_and_make_absolute(const char *p, char **r); -int readlink_and_canonicalize(const char *p, char **r); +int readlink_and_canonicalize(const char *p, const char *root, char **r); int readlink_and_make_absolute_root(const char *root, const char *path, char **ret); int chmod_and_chown(const char *path, mode_t mode, uid_t uid, gid_t gid); @@ -77,3 +77,17 @@ union inotify_event_buffer { }; int inotify_add_watch_fd(int fd, int what, uint32_t mask); + +enum { + CHASE_PREFIX_ROOT = 1, /* If set, the specified path will be prefixed by the specified root before beginning the iteration */ + CHASE_NONEXISTENT = 2, /* If set, it's OK if the path doesn't actually exist. */ +}; + +int chase_symlinks(const char *path_with_prefix, const char *root, unsigned flags, char **ret); + +/* Useful for usage with _cleanup_(), removes a directory and frees the pointer */ +static inline void rmdir_and_free(char *p) { + (void) rmdir(p); + free(p); +} +DEFINE_TRIVIAL_CLEANUP_FUNC(char*, rmdir_and_free); diff --git a/src/systemd/src/basic/hostname-util.c b/src/systemd/src/basic/hostname-util.c index 480f9d9d..732a0ce7 100644 --- a/src/systemd/src/basic/hostname-util.c +++ b/src/systemd/src/basic/hostname-util.c @@ -165,7 +165,6 @@ char* hostname_cleanup(char *s) { *(d++) = *p; dot = false; } - } if (dot && d > s) diff --git a/src/systemd/src/basic/in-addr-util.c b/src/systemd/src/basic/in-addr-util.c index 95230e7d..37dc14f0 100644 --- a/src/systemd/src/basic/in-addr-util.c +++ b/src/systemd/src/basic/in-addr-util.c @@ -33,15 +33,9 @@ #include "util.h" bool in4_addr_is_null(const struct in_addr *a) { - return a->s_addr == 0; -} + assert(a); -bool in6_addr_is_null(const struct in6_addr *a) { - return - a->s6_addr32[0] == 0 && - a->s6_addr32[1] == 0 && - a->s6_addr32[2] == 0 && - a->s6_addr32[3] == 0; + return a->s_addr == 0; } int in_addr_is_null(int family, const union in_addr_union *u) { @@ -51,16 +45,22 @@ int in_addr_is_null(int family, const union in_addr_union *u) { return in4_addr_is_null(&u->in); if (family == AF_INET6) - return in6_addr_is_null(&u->in6); + return IN6_IS_ADDR_UNSPECIFIED(&u->in6); return -EAFNOSUPPORT; } +bool in4_addr_is_link_local(const struct in_addr *a) { + assert(a); + + return (be32toh(a->s_addr) & UINT32_C(0xFFFF0000)) == (UINT32_C(169) << 24 | UINT32_C(254) << 16); +} + int in_addr_is_link_local(int family, const union in_addr_union *u) { assert(u); if (family == AF_INET) - return (be32toh(u->in.s_addr) & UINT32_C(0xFFFF0000)) == (UINT32_C(169) << 24 | UINT32_C(254) << 16); + return in4_addr_is_link_local(&u->in); if (family == AF_INET6) return IN6_IS_ADDR_LINKLOCAL(&u->in6); @@ -68,12 +68,18 @@ int in_addr_is_link_local(int family, const union in_addr_union *u) { return -EAFNOSUPPORT; } +bool in4_addr_is_localhost(const struct in_addr *a) { + assert(a); + + /* All of 127.x.x.x is localhost. */ + return (be32toh(a->s_addr) & UINT32_C(0xFF000000)) == UINT32_C(127) << 24; +} + int in_addr_is_localhost(int family, const union in_addr_union *u) { assert(u); if (family == AF_INET) - /* All of 127.x.x.x is localhost. */ - return (be32toh(u->in.s_addr) & UINT32_C(0xFF000000)) == UINT32_C(127) << 24; + return in4_addr_is_localhost(&u->in); if (family == AF_INET6) return IN6_IS_ADDR_LOOPBACK(&u->in6); @@ -279,15 +285,14 @@ fallback: } int in_addr_from_string(int family, const char *s, union in_addr_union *ret) { - + union in_addr_union buffer; assert(s); - assert(ret); if (!IN_SET(family, AF_INET, AF_INET6)) return -EAFNOSUPPORT; errno = 0; - if (inet_pton(family, s, ret) <= 0) + if (inet_pton(family, s, ret ?: &buffer) <= 0) return errno > 0 ? -errno : -EINVAL; return 0; @@ -297,18 +302,18 @@ int in_addr_from_string_auto(const char *s, int *family, union in_addr_union *re int r; assert(s); - assert(family); - assert(ret); r = in_addr_from_string(AF_INET, s, ret); if (r >= 0) { - *family = AF_INET; + if (family) + *family = AF_INET; return 0; } r = in_addr_from_string(AF_INET6, s, ret); if (r >= 0) { - *family = AF_INET6; + if (family) + *family = AF_INET6; return 0; } diff --git a/src/systemd/src/basic/in-addr-util.h b/src/systemd/src/basic/in-addr-util.h index d60064ae..64a812c3 100644 --- a/src/systemd/src/basic/in-addr-util.h +++ b/src/systemd/src/basic/in-addr-util.h @@ -37,11 +37,14 @@ struct in_addr_data { }; bool in4_addr_is_null(const struct in_addr *a); -bool in6_addr_is_null(const struct in6_addr *a); - int in_addr_is_null(int family, const union in_addr_union *u); + +bool in4_addr_is_link_local(const struct in_addr *a); int in_addr_is_link_local(int family, const union in_addr_union *u); + +bool in4_addr_is_localhost(const struct in_addr *a); int in_addr_is_localhost(int family, const union in_addr_union *u); + int in_addr_equal(int family, const union in_addr_union *a, const union in_addr_union *b); int in_addr_prefix_intersect(int family, const union in_addr_union *a, unsigned aprefixlen, const union in_addr_union *b, unsigned bprefixlen); int in_addr_prefix_next(int family, union in_addr_union *u, unsigned prefixlen); diff --git a/src/systemd/src/basic/list.h b/src/systemd/src/basic/list.h index 5962aa42..c3771a17 100644 --- a/src/systemd/src/basic/list.h +++ b/src/systemd/src/basic/list.h @@ -142,6 +142,8 @@ } else { \ if ((_b->name##_prev = _a->name##_prev)) \ _b->name##_prev->name##_next = _b; \ + else \ + *_head = _b; \ _b->name##_next = _a; \ _a->name##_prev = _b; \ } \ diff --git a/src/systemd/src/basic/log.h b/src/systemd/src/basic/log.h index 322ad6ca..ccf2930f 100644 --- a/src/systemd/src/basic/log.h +++ b/src/systemd/src/basic/log.h @@ -101,18 +101,22 @@ int log_object_internal( const char *func, const char *object_field, const char *object, - const char *format, ...) _printf_(8,9); + const char *extra_field, + const char *extra, + const char *format, ...) _printf_(10,11); int log_object_internalv( int level, int error, - const char*file, + const char *file, int line, const char *func, const char *object_field, const char *object, + const char *extra_field, + const char *extra, const char *format, - va_list ap) _printf_(8,0); + va_list ap) _printf_(9,0); int log_struct_internal( int level, diff --git a/src/systemd/src/basic/parse-util.c b/src/systemd/src/basic/parse-util.c index 27386631..9a7a0bbc 100644 --- a/src/systemd/src/basic/parse-util.c +++ b/src/systemd/src/basic/parse-util.c @@ -579,4 +579,20 @@ int parse_nice(const char *p, int *ret) { *ret = n; return 0; } + +int parse_ip_port(const char *s, uint16_t *ret) { + uint16_t l; + int r; + + r = safe_atou16(s, &l); + if (r < 0) + return r; + + if (l == 0) + return -EINVAL; + + *ret = (uint16_t) l; + + return 0; +} #endif /* NM_IGNORED */ diff --git a/src/systemd/src/basic/parse-util.h b/src/systemd/src/basic/parse-util.h index 461e1cd4..4d132f0d 100644 --- a/src/systemd/src/basic/parse-util.h +++ b/src/systemd/src/basic/parse-util.h @@ -110,3 +110,5 @@ int parse_percent_unbounded(const char *p); int parse_percent(const char *p); int parse_nice(const char *p, int *ret); + +int parse_ip_port(const char *s, uint16_t *ret); diff --git a/src/systemd/src/basic/path-util.c b/src/systemd/src/basic/path-util.c index 86d35bbe..dec95041 100644 --- a/src/systemd/src/basic/path-util.c +++ b/src/systemd/src/basic/path-util.c @@ -36,9 +36,11 @@ #include "alloc-util.h" #include "extract-word.h" #include "fs-util.h" +#include "glob-util.h" #include "log.h" #include "macro.h" #include "missing.h" +#include "parse-util.h" #include "path-util.h" #include "stat-util.h" #include "string-util.h" @@ -84,7 +86,7 @@ char *path_make_absolute(const char *p, const char *prefix) { if (path_is_absolute(p) || !prefix) return strdup(p); - return strjoin(prefix, "/", p, NULL); + return strjoin(prefix, "/", p); } int path_make_absolute_cwd(const char *p, char **ret) { @@ -105,7 +107,7 @@ int path_make_absolute_cwd(const char *p, char **ret) { if (!cwd) return negative_errno(); - c = strjoin(cwd, "/", p, NULL); + c = strjoin(cwd, "/", p); } if (!c) return -ENOMEM; @@ -221,10 +223,11 @@ int path_strv_make_absolute_cwd(char **l) { return 0; } -char **path_strv_resolve(char **l, const char *prefix) { +char **path_strv_resolve(char **l, const char *root) { char **s; unsigned k = 0; bool enomem = false; + int r; if (strv_isempty(l)) return l; @@ -234,17 +237,17 @@ char **path_strv_resolve(char **l, const char *prefix) { * changes on failure. */ STRV_FOREACH(s, l) { - char *t, *u; _cleanup_free_ char *orig = NULL; + char *t, *u; if (!path_is_absolute(*s)) { free(*s); continue; } - if (prefix) { + if (root) { orig = *s; - t = strappend(prefix, orig); + t = prefix_root(root, orig); if (!t) { enomem = true; continue; @@ -252,28 +255,26 @@ char **path_strv_resolve(char **l, const char *prefix) { } else t = *s; - errno = 0; - u = canonicalize_file_name(t); - if (!u) { - if (errno == ENOENT) { - if (prefix) { - u = orig; - orig = NULL; - free(t); - } else - u = t; - } else { + r = chase_symlinks(t, root, 0, &u); + if (r == -ENOENT) { + if (root) { + u = orig; + orig = NULL; free(t); - if (errno == ENOMEM || errno == 0) - enomem = true; + } else + u = t; + } else if (r < 0) { + free(t); - continue; - } - } else if (prefix) { + if (r == -ENOMEM) + enomem = true; + + continue; + } else if (root) { char *x; free(t); - x = path_startswith(u, prefix); + x = path_startswith(u, root); if (x) { /* restore the slash if it was lost */ if (!startswith(x, "/")) @@ -289,9 +290,7 @@ char **path_strv_resolve(char **l, const char *prefix) { } else { /* canonicalized path goes outside of * prefix, keep the original path instead */ - free(u); - u = orig; - orig = NULL; + free_and_replace(u, orig); } } else free(t); @@ -307,12 +306,12 @@ char **path_strv_resolve(char **l, const char *prefix) { return l; } -char **path_strv_resolve_uniq(char **l, const char *prefix) { +char **path_strv_resolve_uniq(char **l, const char *root) { if (strv_isempty(l)) return l; - if (!path_strv_resolve(l, prefix)) + if (!path_strv_resolve(l, root)) return NULL; return strv_uniq(l); @@ -359,6 +358,16 @@ char* path_startswith(const char *path, const char *prefix) { assert(path); assert(prefix); + /* Returns a pointer to the start of the first component after the parts matched by + * the prefix, iff + * - both paths are absolute or both paths are relative, + * and + * - each component in prefix in turn matches a component in path at the same position. + * An empty string will be returned when the prefix and path are equivalent. + * + * Returns NULL otherwise. + */ + if ((path[0] == '/') != (prefix[0] == '/')) return NULL; @@ -449,13 +458,11 @@ char* path_join(const char *root, const char *path, const char *rest) { return strjoin(root, endswith(root, "/") ? "" : "/", path[0] == '/' ? path+1 : path, rest ? (endswith(path, "/") ? "" : "/") : NULL, - rest && rest[0] == '/' ? rest+1 : rest, - NULL); + rest && rest[0] == '/' ? rest+1 : rest); else return strjoin(path, rest ? (endswith(path, "/") ? "" : "/") : NULL, - rest && rest[0] == '/' ? rest+1 : rest, - NULL); + rest && rest[0] == '/' ? rest+1 : rest); } int find_binary(const char *name, char **ret) { @@ -499,7 +506,7 @@ int find_binary(const char *name, char **ret) { if (!path_is_absolute(element)) continue; - j = strjoin(element, "/", name, NULL); + j = strjoin(element, "/", name); if (!j) return -ENOMEM; @@ -817,8 +824,79 @@ bool is_device_path(const char *path) { /* Returns true on paths that refer to a device, either in * sysfs or in /dev */ - return - path_startswith(path, "/dev/") || - path_startswith(path, "/sys/"); + return path_startswith(path, "/dev/") || + path_startswith(path, "/sys/"); +} + +bool is_deviceallow_pattern(const char *path) { + return path_startswith(path, "/dev/") || + startswith(path, "block-") || + startswith(path, "char-"); +} + +int systemd_installation_has_version(const char *root, unsigned minimal_version) { + const char *pattern; + int r; + + /* Try to guess if systemd installation is later than the specified version. This + * is hacky and likely to yield false negatives, particularly if the installation + * is non-standard. False positives should be relatively rare. + */ + + NULSTR_FOREACH(pattern, + /* /lib works for systems without usr-merge, and for systems with a sane + * usr-merge, where /lib is a symlink to /usr/lib. /usr/lib is necessary + * for Gentoo which does a merge without making /lib a symlink. + */ + "lib/systemd/libsystemd-shared-*.so\0" + "usr/lib/systemd/libsystemd-shared-*.so\0") { + + _cleanup_strv_free_ char **names = NULL; + _cleanup_free_ char *path = NULL; + char *c, **name; + + path = prefix_root(root, pattern); + if (!path) + return -ENOMEM; + + r = glob_extend(&names, path); + if (r == -ENOENT) + continue; + if (r < 0) + return r; + + assert_se((c = endswith(path, "*.so"))); + *c = '\0'; /* truncate the glob part */ + + STRV_FOREACH(name, names) { + /* This is most likely to run only once, hence let's not optimize anything. */ + char *t, *t2; + unsigned version; + + t = startswith(*name, path); + if (!t) + continue; + + t2 = endswith(t, ".so"); + if (!t2) + continue; + + t2[0] = '\0'; /* truncate the suffix */ + + r = safe_atou(t, &version); + if (r < 0) { + log_debug_errno(r, "Found libsystemd shared at \"%s.so\", but failed to parse version: %m", *name); + continue; + } + + log_debug("Found libsystemd shared at \"%s.so\", version %u (%s).", + *name, version, + version >= minimal_version ? "OK" : "too old"); + if (version >= minimal_version) + return true; + } + } + + return false; } #endif /* NM_IGNORED */ diff --git a/src/systemd/src/basic/path-util.h b/src/systemd/src/basic/path-util.h index a27c13fc..349cdac7 100644 --- a/src/systemd/src/basic/path-util.h +++ b/src/systemd/src/basic/path-util.h @@ -24,6 +24,7 @@ #include <stddef.h> #include "macro.h" +#include "string-util.h" #include "time-util.h" #define DEFAULT_PATH_NORMAL "/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin" @@ -65,9 +66,21 @@ static inline bool path_equal_ptr(const char *a, const char *b) { _found; \ }) +#define PATH_STARTSWITH_SET(p, ...) \ + ({ \ + char **s; \ + bool _found = false; \ + STRV_FOREACH(s, STRV_MAKE(__VA_ARGS__)) \ + if (path_startswith(p, *s)) { \ + _found = true; \ + break; \ + } \ + _found; \ + }) + int path_strv_make_absolute_cwd(char **l); -char** path_strv_resolve(char **l, const char *prefix); -char** path_strv_resolve_uniq(char **l, const char *prefix); +char** path_strv_resolve(char **l, const char *root); +char** path_strv_resolve_uniq(char **l, const char *root); int find_binary(const char *name, char **filename); @@ -125,3 +138,6 @@ char *file_in_same_dir(const char *path, const char *filename); bool hidden_or_backup_file(const char *filename) _pure_; bool is_device_path(const char *path); +bool is_deviceallow_pattern(const char *path); + +int systemd_installation_has_version(const char *root, unsigned minimal_version); diff --git a/src/systemd/src/basic/prioq.c b/src/systemd/src/basic/prioq.c index 809e2122..64ad638e 100644 --- a/src/systemd/src/basic/prioq.c +++ b/src/systemd/src/basic/prioq.c @@ -64,9 +64,7 @@ Prioq* prioq_free(Prioq *q) { return NULL; free(q->items); - free(q); - - return NULL; + return mfree(q); } int prioq_ensure_allocated(Prioq **q, compare_func_t compare_func) { diff --git a/src/systemd/src/basic/socket-util.c b/src/systemd/src/basic/socket-util.c index be57d829..57bc4b70 100644 --- a/src/systemd/src/basic/socket-util.c +++ b/src/systemd/src/basic/socket-util.c @@ -36,7 +36,7 @@ #include "alloc-util.h" #include "fd-util.h" #include "fileio.h" -#include "formats-util.h" +#include "format-util.h" #include "log.h" #include "macro.h" #include "missing.h" @@ -444,7 +444,7 @@ const char* socket_address_get_path(const SocketAddress *a) { } bool socket_ipv6_is_supported(void) { - if (access("/proc/net/sockstat6", F_OK) != 0) + if (access("/proc/net/if_inet6", F_OK) != 0) return false; return true; @@ -1064,3 +1064,20 @@ struct cmsghdr* cmsg_find(struct msghdr *mh, int level, int type, socklen_t leng return NULL; } + +int socket_ioctl_fd(void) { + int fd; + + /* Create a socket to invoke the various network interface ioctl()s on. Traditionally only AF_INET was good for + * that. Since kernel 4.6 AF_NETLINK works for this too. We first try to use AF_INET hence, but if that's not + * available (for example, because it is made unavailable via SECCOMP or such), we'll fall back to the more + * generic AF_NETLINK. */ + + fd = socket(AF_INET, SOCK_DGRAM|SOCK_CLOEXEC, 0); + if (fd < 0) + fd = socket(AF_NETLINK, SOCK_RAW|SOCK_CLOEXEC, NETLINK_GENERIC); + if (fd < 0) + return -errno; + + return fd; +} diff --git a/src/systemd/src/basic/socket-util.h b/src/systemd/src/basic/socket-util.h index 2536b085..2ef572ba 100644 --- a/src/systemd/src/basic/socket-util.h +++ b/src/systemd/src/basic/socket-util.h @@ -154,3 +154,5 @@ struct cmsghdr* cmsg_find(struct msghdr *mh, int level, int type, socklen_t leng 1 + strnlen(_sa->sun_path+1, sizeof(_sa->sun_path)-1) : \ strnlen(_sa->sun_path, sizeof(_sa->sun_path))); \ }) + +int socket_ioctl_fd(void); diff --git a/src/systemd/src/basic/sparse-endian.h b/src/systemd/src/basic/sparse-endian.h index c913fda8..a3573b84 100644 --- a/src/systemd/src/basic/sparse-endian.h +++ b/src/systemd/src/basic/sparse-endian.h @@ -26,19 +26,19 @@ #include <stdint.h> #ifdef __CHECKER__ -#define __bitwise __attribute__((bitwise)) -#define __force __attribute__((force)) +#define __sd_bitwise __attribute__((bitwise)) +#define __sd_force __attribute__((force)) #else -#define __bitwise -#define __force +#define __sd_bitwise +#define __sd_force #endif -typedef uint16_t __bitwise le16_t; -typedef uint16_t __bitwise be16_t; -typedef uint32_t __bitwise le32_t; -typedef uint32_t __bitwise be32_t; -typedef uint64_t __bitwise le64_t; -typedef uint64_t __bitwise be64_t; +typedef uint16_t __sd_bitwise le16_t; +typedef uint16_t __sd_bitwise be16_t; +typedef uint32_t __sd_bitwise le32_t; +typedef uint32_t __sd_bitwise be32_t; +typedef uint64_t __sd_bitwise le64_t; +typedef uint64_t __sd_bitwise be64_t; #undef htobe16 #undef htole16 @@ -69,20 +69,23 @@ typedef uint64_t __bitwise be64_t; #define bswap_64_on_be(x) __bswap_64(x) #endif -static inline le16_t htole16(uint16_t value) { return (le16_t __force) bswap_16_on_be(value); } -static inline le32_t htole32(uint32_t value) { return (le32_t __force) bswap_32_on_be(value); } -static inline le64_t htole64(uint64_t value) { return (le64_t __force) bswap_64_on_be(value); } +static inline le16_t htole16(uint16_t value) { return (le16_t __sd_force) bswap_16_on_be(value); } +static inline le32_t htole32(uint32_t value) { return (le32_t __sd_force) bswap_32_on_be(value); } +static inline le64_t htole64(uint64_t value) { return (le64_t __sd_force) bswap_64_on_be(value); } -static inline be16_t htobe16(uint16_t value) { return (be16_t __force) bswap_16_on_le(value); } -static inline be32_t htobe32(uint32_t value) { return (be32_t __force) bswap_32_on_le(value); } -static inline be64_t htobe64(uint64_t value) { return (be64_t __force) bswap_64_on_le(value); } +static inline be16_t htobe16(uint16_t value) { return (be16_t __sd_force) bswap_16_on_le(value); } +static inline be32_t htobe32(uint32_t value) { return (be32_t __sd_force) bswap_32_on_le(value); } +static inline be64_t htobe64(uint64_t value) { return (be64_t __sd_force) bswap_64_on_le(value); } -static inline uint16_t le16toh(le16_t value) { return bswap_16_on_be((uint16_t __force)value); } -static inline uint32_t le32toh(le32_t value) { return bswap_32_on_be((uint32_t __force)value); } -static inline uint64_t le64toh(le64_t value) { return bswap_64_on_be((uint64_t __force)value); } +static inline uint16_t le16toh(le16_t value) { return bswap_16_on_be((uint16_t __sd_force)value); } +static inline uint32_t le32toh(le32_t value) { return bswap_32_on_be((uint32_t __sd_force)value); } +static inline uint64_t le64toh(le64_t value) { return bswap_64_on_be((uint64_t __sd_force)value); } -static inline uint16_t be16toh(be16_t value) { return bswap_16_on_le((uint16_t __force)value); } -static inline uint32_t be32toh(be32_t value) { return bswap_32_on_le((uint32_t __force)value); } -static inline uint64_t be64toh(be64_t value) { return bswap_64_on_le((uint64_t __force)value); } +static inline uint16_t be16toh(be16_t value) { return bswap_16_on_le((uint16_t __sd_force)value); } +static inline uint32_t be32toh(be32_t value) { return bswap_32_on_le((uint32_t __sd_force)value); } +static inline uint64_t be64toh(be64_t value) { return bswap_64_on_le((uint64_t __sd_force)value); } + +#undef __sd_bitwise +#undef __sd_force #endif /* SPARSE_ENDIAN_H */ diff --git a/src/systemd/src/basic/string-util.c b/src/systemd/src/basic/string-util.c index b4e774cc..aeb9e2a9 100644 --- a/src/systemd/src/basic/string-util.c +++ b/src/systemd/src/basic/string-util.c @@ -220,7 +220,7 @@ char *strappend(const char *s, const char *suffix) { return strnappend(s, suffix, suffix ? strlen(suffix) : 0); } -char *strjoin(const char *x, ...) { +char *strjoin_real(const char *x, ...) { va_list ap; size_t l; char *r, *p; @@ -446,7 +446,7 @@ static char *ascii_ellipsize_mem(const char *s, size_t old_length, size_t new_le if (old_length <= 3 || old_length <= new_length) return strndup(s, old_length); - r = new0(char, new_length+1); + r = new0(char, new_length+3); if (!r) return NULL; @@ -456,12 +456,12 @@ static char *ascii_ellipsize_mem(const char *s, size_t old_length, size_t new_le x = new_length - 3; memcpy(r, s, x); - r[x] = '.'; - r[x+1] = '.'; - r[x+2] = '.'; + r[x] = 0xe2; /* tri-dot ellipsis: … */ + r[x+1] = 0x80; + r[x+2] = 0xa6; memcpy(r + x + 3, - s + old_length - (new_length - x - 3), - new_length - x - 3); + s + old_length - (new_length - x - 1), + new_length - x - 1); return r; } @@ -614,8 +614,7 @@ char *strreplace(const char *text, const char *old_string, const char *new_strin return r; oom: - free(r); - return NULL; + return mfree(r); } char *strip_tab_ansi(char **ibuf, size_t *_isz) { @@ -686,8 +685,7 @@ char *strip_tab_ansi(char **ibuf, size_t *_isz) { if (ferror(f)) { fclose(f); - free(obuf); - return NULL; + return mfree(obuf); } fclose(f); diff --git a/src/systemd/src/basic/string-util.h b/src/systemd/src/basic/string-util.h index b75aba63..e99f7964 100644 --- a/src/systemd/src/basic/string-util.h +++ b/src/systemd/src/basic/string-util.h @@ -70,6 +70,10 @@ static inline const char *empty_to_null(const char *p) { return isempty(p) ? NULL : p; } +static inline const char *strdash_if_empty(const char *str) { + return isempty(str) ? "-" : str; +} + static inline char *startswith(const char *s, const char *prefix) { size_t l; @@ -103,16 +107,14 @@ const char* split(const char **state, size_t *l, const char *separator, bool quo #define FOREACH_WORD_SEPARATOR(word, length, s, separator, state) \ _FOREACH_WORD(word, length, s, separator, false, state) -#define FOREACH_WORD_QUOTED(word, length, s, state) \ - _FOREACH_WORD(word, length, s, WHITESPACE, true, state) - #define _FOREACH_WORD(word, length, s, separator, quoted, state) \ for ((state) = (s), (word) = split(&(state), &(length), (separator), (quoted)); (word); (word) = split(&(state), &(length), (separator), (quoted))) char *strappend(const char *s, const char *suffix); char *strnappend(const char *s, const char *suffix, size_t length); -char *strjoin(const char *x, ...) _sentinel_; +char *strjoin_real(const char *x, ...) _sentinel_; +#define strjoin(a, ...) strjoin_real((a), __VA_ARGS__, NULL) #define strjoina(a, ...) \ ({ \ diff --git a/src/systemd/src/basic/strv.c b/src/systemd/src/basic/strv.c index eeb8c1e0..a3660f08 100644 --- a/src/systemd/src/basic/strv.c +++ b/src/systemd/src/basic/strv.c @@ -89,8 +89,7 @@ void strv_clear(char **l) { char **strv_free(char **l) { strv_clear(l); - free(l); - return NULL; + return mfree(l); } char **strv_free_erase(char **l) { @@ -430,8 +429,7 @@ char *strv_join_quoted(char **l) { return buf; oom: - free(buf); - return NULL; + return mfree(buf); } int strv_push(char ***l, char *value) { @@ -873,8 +871,7 @@ char ***strv_free_free(char ***l) { for (i = l; *i; i++) strv_free(*i); - free(l); - return NULL; + return mfree(l); } char **strv_skip(char **l, size_t n) { diff --git a/src/systemd/src/basic/strv.h b/src/systemd/src/basic/strv.h index 683ce83a..385ad177 100644 --- a/src/systemd/src/basic/strv.h +++ b/src/systemd/src/basic/strv.h @@ -96,10 +96,13 @@ bool strv_overlap(char **a, char **b) _pure_; #define STRV_FOREACH(s, l) \ for ((s) = (l); (s) && *(s); (s)++) -#define STRV_FOREACH_BACKWARDS(s, l) \ - STRV_FOREACH(s, l) \ - ; \ - for ((s)--; (l) && ((s) >= (l)); (s)--) +#define STRV_FOREACH_BACKWARDS(s, l) \ + for (s = ({ \ + char **_l = l; \ + _l ? _l + strv_length(_l) - 1U : NULL; \ + }); \ + (l) && ((s) >= (l)); \ + (s)--) #define STRV_FOREACH_PAIR(x, y, l) \ for ((x) = (l), (y) = (x+1); (x) && *(x) && *(y); (x) += 2, (y) = (x + 1)) @@ -141,6 +144,11 @@ void strv_print(char **l); }) #define STR_IN_SET(x, ...) strv_contains(STRV_MAKE(__VA_ARGS__), x) +#define STRPTR_IN_SET(x, ...) \ + ({ \ + const char* _x = (x); \ + _x && strv_contains(STRV_MAKE(__VA_ARGS__), _x); \ + }) #define FOREACH_STRING(x, ...) \ for (char **_l = ({ \ diff --git a/src/systemd/src/basic/time-util.c b/src/systemd/src/basic/time-util.c index 212c8f4e..f6de8ca5 100644 --- a/src/systemd/src/basic/time-util.c +++ b/src/systemd/src/basic/time-util.c @@ -42,8 +42,6 @@ #include "strv.h" #include "time-util.h" -static nsec_t timespec_load_nsec(const struct timespec *ts); - static clockid_t map_clock_id(clockid_t c) { /* Some more exotic archs (s390, ppc, …) lack the "ALARM" flavour of the clocks. Thus, clock_gettime() will @@ -200,7 +198,7 @@ usec_t timespec_load(const struct timespec *ts) { (usec_t) ts->tv_nsec / NSEC_PER_USEC; } -static nsec_t timespec_load_nsec(const struct timespec *ts) { +nsec_t timespec_load_nsec(const struct timespec *ts) { assert(ts); if (ts->tv_sec == (time_t) -1 && ts->tv_nsec == (long) -1) @@ -314,7 +312,7 @@ static char *format_timestamp_internal( if (n + 8 > l) return NULL; /* Microseconds part doesn't fit. */ - sprintf(buf + n, ".%06llu", (unsigned long long) (t % USEC_PER_SEC)); + sprintf(buf + n, ".%06"PRI_USEC, t % USEC_PER_SEC); } /* Append the timezone */ @@ -505,11 +503,11 @@ char *format_timespan(char *buf, size_t l, usec_t t, usec_t accuracy) { if (j > 0) { k = snprintf(p, l, - "%s"USEC_FMT".%0*llu%s", + "%s"USEC_FMT".%0*"PRI_USEC"%s", p > buf ? " " : "", a, j, - (unsigned long long) b, + b, table[i].suffix); t = 0; @@ -890,6 +888,7 @@ static char* extract_multiplier(char *p, usec_t *multiplier) { { "y", USEC_PER_YEAR }, { "usec", 1ULL }, { "us", 1ULL }, + { "µs", 1ULL }, }; unsigned i; @@ -1023,6 +1022,7 @@ int parse_nsec(const char *t, nsec_t *nsec) { { "y", NSEC_PER_YEAR }, { "usec", NSEC_PER_USEC }, { "us", NSEC_PER_USEC }, + { "µs", NSEC_PER_USEC }, { "nsec", 1ULL }, { "ns", 1ULL }, { "", 1ULL }, /* default is nsec */ @@ -1329,7 +1329,7 @@ unsigned long usec_to_jiffies(usec_t u) { r = sysconf(_SC_CLK_TCK); assert(r > 0); - hz = (unsigned long) r; + hz = r; } return DIV_ROUND_UP(u , USEC_PER_SEC / hz); diff --git a/src/systemd/src/basic/time-util.h b/src/systemd/src/basic/time-util.h index 99be5ce6..f67a4474 100644 --- a/src/systemd/src/basic/time-util.h +++ b/src/systemd/src/basic/time-util.h @@ -29,8 +29,10 @@ typedef uint64_t usec_t; typedef uint64_t nsec_t; -#define NSEC_FMT "%" PRIu64 -#define USEC_FMT "%" PRIu64 +#define PRI_NSEC PRIu64 +#define PRI_USEC PRIu64 +#define NSEC_FMT "%" PRI_NSEC +#define USEC_FMT "%" PRI_USEC #include "macro.h" @@ -111,6 +113,7 @@ static inline bool triple_timestamp_is_set(triple_timestamp *ts) { usec_t triple_timestamp_by_clock(triple_timestamp *ts, clockid_t clock); usec_t timespec_load(const struct timespec *ts) _pure_; +nsec_t timespec_load_nsec(const struct timespec *ts) _pure_; struct timespec *timespec_store(struct timespec *ts, usec_t u); usec_t timeval_load(const struct timeval *tv) _pure_; diff --git a/src/systemd/src/basic/util.c b/src/systemd/src/basic/util.c index 79c7aa46..09651e7d 100644 --- a/src/systemd/src/basic/util.c +++ b/src/systemd/src/basic/util.c @@ -20,7 +20,6 @@ #include "nm-sd-adapt.h" #include <alloca.h> -#include <dirent.h> #include <errno.h> #include <fcntl.h> #include <sched.h> @@ -43,7 +42,7 @@ #include "dirent-util.h" #include "fd-util.h" #include "fileio.h" -#include "formats-util.h" +#include "format-util.h" #include "hashmap.h" #include "hostname-util.h" #include "log.h" @@ -136,7 +135,7 @@ static int do_execute(char **directories, usec_t timeout, char *argv[]) { if (r < 0) return log_oom(); - path = strjoin(*directory, "/", de->d_name, NULL); + path = strjoin(*directory, "/", de->d_name); if (!path) return log_oom(); @@ -472,7 +471,7 @@ bool in_initrd(void) { * 2. the root file system must be a memory file system * * The second check is extra paranoia, since misdetecting an - * initrd can have bad bad consequences due the initrd + * initrd can have bad consequences due the initrd * emptying when transititioning to the main systemd. */ @@ -498,7 +497,7 @@ void *xbsearch_r(const void *key, const void *base, size_t nmemb, size_t size, u = nmemb; while (l < u) { idx = (l + u) / 2; - p = (void *)(((const char *) base) + (idx * size)); + p = (const char *) base + idx * size; comparison = compar(key, p, arg); if (comparison < 0) u = idx; @@ -513,28 +512,17 @@ void *xbsearch_r(const void *key, const void *base, size_t nmemb, size_t size, int on_ac_power(void) { bool found_offline = false, found_online = false; _cleanup_closedir_ DIR *d = NULL; + struct dirent *de; d = opendir("/sys/class/power_supply"); if (!d) return errno == ENOENT ? true : -errno; - for (;;) { - struct dirent *de; + FOREACH_DIRENT(de, d, return -errno) { _cleanup_close_ int fd = -1, device = -1; char contents[6]; ssize_t n; - errno = 0; - de = readdir(d); - if (!de && errno > 0) - return -errno; - - if (!de) - break; - - if (hidden_or_backup_file(de->d_name)) - continue; - device = openat(dirfd(d), de->d_name, O_DIRECTORY|O_RDONLY|O_CLOEXEC|O_NOCTTY); if (device < 0) { if (errno == ENOENT || errno == ENOTDIR) diff --git a/src/systemd/src/basic/util.h b/src/systemd/src/basic/util.h index bb2fc318..c3802a81 100644 --- a/src/systemd/src/basic/util.h +++ b/src/systemd/src/basic/util.h @@ -41,7 +41,7 @@ #include <time.h> #include <unistd.h> -#include "formats-util.h" +#include "format-util.h" #include "macro.h" #include "missing.h" #include "time-util.h" diff --git a/src/systemd/src/libsystemd-network/dhcp-internal.h b/src/systemd/src/libsystemd-network/dhcp-internal.h index 99f69089..3fdf02da 100644 --- a/src/systemd/src/libsystemd-network/dhcp-internal.h +++ b/src/systemd/src/libsystemd-network/dhcp-internal.h @@ -30,10 +30,11 @@ #include "dhcp-protocol.h" #include "socket-util.h" -int dhcp_network_bind_raw_socket(int index, union sockaddr_union *link, +int dhcp_network_bind_raw_socket(int ifindex, union sockaddr_union *link, uint32_t xid, const uint8_t *mac_addr, - size_t mac_addr_len, uint16_t arp_type); -int dhcp_network_bind_udp_socket(be32_t address, uint16_t port); + size_t mac_addr_len, uint16_t arp_type, + uint16_t port); +int dhcp_network_bind_udp_socket(int ifindex, be32_t address, uint16_t port); int dhcp_network_send_raw_socket(int s, const union sockaddr_union *link, const void *packet, size_t len); int dhcp_network_send_udp_socket(int s, be32_t address, uint16_t port, @@ -57,7 +58,7 @@ void dhcp_packet_append_ip_headers(DHCPPacket *packet, be32_t source_addr, uint16_t source, be32_t destination_addr, uint16_t destination, uint16_t len); -int dhcp_packet_verify_headers(DHCPPacket *packet, size_t len, bool checksum); +int dhcp_packet_verify_headers(DHCPPacket *packet, size_t len, bool checksum, uint16_t port); /* If we are invoking callbacks of a dhcp-client, ensure unreffing the * client from the callback doesn't destroy the object we are working diff --git a/src/systemd/src/libsystemd-network/dhcp-network.c b/src/systemd/src/libsystemd-network/dhcp-network.c index f1856d0a..7ad0ec37 100644 --- a/src/systemd/src/libsystemd-network/dhcp-network.c +++ b/src/systemd/src/libsystemd-network/dhcp-network.c @@ -21,6 +21,7 @@ #include <errno.h> #include <net/ethernet.h> +#include <net/if.h> #include <net/if_arp.h> #include <stdio.h> #include <string.h> @@ -38,7 +39,8 @@ static int _bind_raw_socket(int ifindex, union sockaddr_union *link, size_t mac_addr_len, const uint8_t *bcast_addr, const struct ether_addr *eth_mac, - uint16_t arp_type, uint8_t dhcp_hlen) { + uint16_t arp_type, uint8_t dhcp_hlen, + uint16_t port) { struct sock_filter filter[] = { BPF_STMT(BPF_LD + BPF_W + BPF_LEN, 0), /* A <- packet length */ BPF_JUMP(BPF_JMP + BPF_JGE + BPF_K, sizeof(DHCPPacket), 1, 0), /* packet >= DHCPPacket ? */ @@ -55,7 +57,7 @@ static int _bind_raw_socket(int ifindex, union sockaddr_union *link, BPF_JUMP(BPF_JMP + BPF_JEQ + BPF_K, 0, 1, 0), /* A == 0 ? */ BPF_STMT(BPF_RET + BPF_K, 0), /* ignore */ BPF_STMT(BPF_LD + BPF_H + BPF_ABS, offsetof(DHCPPacket, udp.dest)), /* A <- UDP destination port */ - BPF_JUMP(BPF_JMP + BPF_JEQ + BPF_K, DHCP_PORT_CLIENT, 1, 0), /* UDP destination port == DHCP client port ? */ + BPF_JUMP(BPF_JMP + BPF_JEQ + BPF_K, port, 1, 0), /* UDP destination port == DHCP client port ? */ BPF_STMT(BPF_RET + BPF_K, 0), /* ignore */ BPF_STMT(BPF_LD + BPF_B + BPF_ABS, offsetof(DHCPPacket, dhcp.op)), /* A <- DHCP op */ BPF_JUMP(BPF_JMP + BPF_JEQ + BPF_K, BOOTREPLY, 1, 0), /* op == BOOTREPLY ? */ @@ -127,7 +129,8 @@ static int _bind_raw_socket(int ifindex, union sockaddr_union *link, int dhcp_network_bind_raw_socket(int ifindex, union sockaddr_union *link, uint32_t xid, const uint8_t *mac_addr, - size_t mac_addr_len, uint16_t arp_type) { + size_t mac_addr_len, uint16_t arp_type, + uint16_t port) { static const uint8_t eth_bcast[] = { 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF }; /* Default broadcast address for IPoIB */ static const uint8_t ib_bcast[] = { @@ -153,16 +156,17 @@ int dhcp_network_bind_raw_socket(int ifindex, union sockaddr_union *link, return -EINVAL; return _bind_raw_socket(ifindex, link, xid, mac_addr, mac_addr_len, - bcast_addr, ð_mac, arp_type, dhcp_hlen); + bcast_addr, ð_mac, arp_type, dhcp_hlen, port); } -int dhcp_network_bind_udp_socket(be32_t address, uint16_t port) { +int dhcp_network_bind_udp_socket(int ifindex, be32_t address, uint16_t port) { union sockaddr_union src = { .in.sin_family = AF_INET, .in.sin_port = htobe16(port), .in.sin_addr.s_addr = address, }; _cleanup_close_ int s = -1; + char ifname[IF_NAMESIZE] = ""; int r, on = 1, tos = IPTOS_CLASS_CS6; s = socket(AF_INET, SOCK_DGRAM | SOCK_CLOEXEC | SOCK_NONBLOCK, 0); @@ -177,6 +181,15 @@ int dhcp_network_bind_udp_socket(be32_t address, uint16_t port) { if (r < 0) return -errno; + if (ifindex > 0) { + if (if_indextoname(ifindex, ifname) == 0) + return -errno; + + r = setsockopt(s, SOL_SOCKET, SO_BINDTODEVICE, ifname, strlen(ifname)); + if (r < 0) + return -errno; + } + if (address == INADDR_ANY) { r = setsockopt(s, IPPROTO_IP, IP_PKTINFO, &on, sizeof(on)); if (r < 0) @@ -185,6 +198,7 @@ int dhcp_network_bind_udp_socket(be32_t address, uint16_t port) { r = setsockopt(s, SOL_SOCKET, SO_BROADCAST, &on, sizeof(on)); if (r < 0) return -errno; + } else { r = setsockopt(s, IPPROTO_IP, IP_FREEBIND, &on, sizeof(on)); if (r < 0) diff --git a/src/systemd/src/libsystemd-network/dhcp-packet.c b/src/systemd/src/libsystemd-network/dhcp-packet.c index 90d09912..27410520 100644 --- a/src/systemd/src/libsystemd-network/dhcp-packet.c +++ b/src/systemd/src/libsystemd-network/dhcp-packet.c @@ -116,7 +116,7 @@ void dhcp_packet_append_ip_headers(DHCPPacket *packet, be32_t source_addr, packet->ip.check = dhcp_packet_checksum((uint8_t*)&packet->ip, DHCP_IP_SIZE); } -int dhcp_packet_verify_headers(DHCPPacket *packet, size_t len, bool checksum) { +int dhcp_packet_verify_headers(DHCPPacket *packet, size_t len, bool checksum, uint16_t port) { size_t hdrlen; assert(packet); @@ -162,10 +162,10 @@ int dhcp_packet_verify_headers(DHCPPacket *packet, size_t len, bool checksum) { return -EINVAL; } - if (be16toh(packet->udp.dest) != DHCP_PORT_CLIENT) { + if (be16toh(packet->udp.dest) != port) { log_debug("ignoring packet: to port %u, which " "is not the DHCP client port (%u)", - be16toh(packet->udp.dest), DHCP_PORT_CLIENT); + be16toh(packet->udp.dest), port); return -EINVAL; } diff --git a/src/systemd/src/libsystemd-network/network-internal.c b/src/systemd/src/libsystemd-network/network-internal.c index 46bddfeb..285a73e3 100644 --- a/src/systemd/src/libsystemd-network/network-internal.c +++ b/src/systemd/src/libsystemd-network/network-internal.c @@ -89,6 +89,28 @@ int net_get_unique_predictable_data(struct udev_device *device, uint64_t *result return 0; } +static bool net_condition_test_strv(char * const *raw_patterns, + const char *string) { + if (strv_isempty(raw_patterns)) + return true; + + /* If the patterns begin with "!", edit it out and negate the test. */ + if (raw_patterns[0][0] == '!') { + char **patterns; + unsigned i, length; + + length = strv_length(raw_patterns) + 1; /* Include the NULL. */ + patterns = newa(char*, length); + patterns[0] = raw_patterns[0] + 1; /* Skip the "!". */ + for (i = 1; i < length; i++) + patterns[i] = raw_patterns[i]; + + return !string || !strv_fnmatch(patterns, string, 0); + } + + return string && strv_fnmatch(raw_patterns, string, 0); +} + bool net_match_config(const struct ether_addr *match_mac, char * const *match_paths, char * const *match_drivers, @@ -120,20 +142,16 @@ bool net_match_config(const struct ether_addr *match_mac, if (match_mac && (!dev_mac || memcmp(match_mac, dev_mac, ETH_ALEN))) return false; - if (!strv_isempty(match_paths) && - (!dev_path || !strv_fnmatch(match_paths, dev_path, 0))) + if (!net_condition_test_strv(match_paths, dev_path)) return false; - if (!strv_isempty(match_drivers) && - (!dev_driver || !strv_fnmatch(match_drivers, dev_driver, 0))) + if (!net_condition_test_strv(match_drivers, dev_driver)) return false; - if (!strv_isempty(match_types) && - (!dev_type || !strv_fnmatch_or_empty(match_types, dev_type, 0))) + if (!net_condition_test_strv(match_types, dev_type)) return false; - if (!strv_isempty(match_names) && - (!dev_name || !strv_fnmatch_or_empty(match_names, dev_name, 0))) + if (!net_condition_test_strv(match_names, dev_name)) return false; return true; diff --git a/src/systemd/src/libsystemd-network/sd-dhcp-client.c b/src/systemd/src/libsystemd-network/sd-dhcp-client.c index f740075a..7809a812 100644 --- a/src/systemd/src/libsystemd-network/sd-dhcp-client.c +++ b/src/systemd/src/libsystemd-network/sd-dhcp-client.c @@ -57,6 +57,7 @@ struct sd_dhcp_client { sd_event_source *timeout_resend; int ifindex; int fd; + uint16_t port; union sockaddr_union link; sd_event_source *receive_message; bool request_broadcast; @@ -389,43 +390,32 @@ int sd_dhcp_client_set_hostname( sd_dhcp_client *client, const char *hostname) { - char *new_hostname = NULL; - assert_return(client, -EINVAL); - if (!hostname_is_valid(hostname, false) && !dns_name_is_valid(hostname)) + /* Refuse hostnames that neither qualify as DNS nor as Linux hosntames */ + if (hostname && + !(hostname_is_valid(hostname, false) || dns_name_is_valid(hostname) > 0)) return -EINVAL; - if (streq_ptr(client->hostname, hostname)) - return 0; - - if (hostname) { - new_hostname = strdup(hostname); - if (!new_hostname) - return -ENOMEM; - } - - free(client->hostname); - client->hostname = new_hostname; - - return 0; + return free_and_strdup(&client->hostname, hostname); } int sd_dhcp_client_set_vendor_class_identifier( sd_dhcp_client *client, const char *vci) { - char *new_vci = NULL; - assert_return(client, -EINVAL); - new_vci = strdup(vci); - if (!new_vci) - return -ENOMEM; + return free_and_strdup(&client->vendor_class_identifier, vci); +} - free(client->vendor_class_identifier); +int sd_dhcp_client_set_client_port( + sd_dhcp_client *client, + uint16_t port) { + + assert_return(client, -EINVAL); - client->vendor_class_identifier = new_vci; + client->port = port; return 0; } @@ -672,7 +662,7 @@ static int dhcp_client_send_raw( DHCPPacket *packet, size_t len) { - dhcp_packet_append_ip_headers(packet, INADDR_ANY, DHCP_PORT_CLIENT, + dhcp_packet_append_ip_headers(packet, INADDR_ANY, client->port, INADDR_BROADCAST, DHCP_PORT_SERVER, len); return dhcp_network_send_raw_socket(client->fd, &client->link, @@ -1124,7 +1114,7 @@ static int client_start_delayed(sd_dhcp_client *client) { r = dhcp_network_bind_raw_socket(client->ifindex, &client->link, client->xid, client->mac_addr, - client->mac_addr_len, client->arp_type); + client->mac_addr_len, client->arp_type, client->port); if (r < 0) { client_stop(client, r); return r; @@ -1174,7 +1164,8 @@ static int client_timeout_t2(sd_event_source *s, uint64_t usec, void *userdata) r = dhcp_network_bind_raw_socket(client->ifindex, &client->link, client->xid, client->mac_addr, - client->mac_addr_len, client->arp_type); + client->mac_addr_len, client->arp_type, + client->port); if (r < 0) { client_stop(client, r); return 0; @@ -1559,8 +1550,7 @@ static int client_handle_message(sd_dhcp_client *client, DHCPMessage *message, i goto error; } - r = dhcp_network_bind_udp_socket(client->lease->address, - DHCP_PORT_CLIENT); + r = dhcp_network_bind_udp_socket(client->ifindex, client->lease->address, client->port); if (r < 0) { log_dhcp_client(client, "could not bind UDP socket"); goto error; @@ -1770,7 +1760,7 @@ static int client_receive_message_raw( } } - r = dhcp_packet_verify_headers(packet, len, checksum); + r = dhcp_packet_verify_headers(packet, len, checksum, client->port); if (r < 0) return 0; @@ -1877,9 +1867,7 @@ sd_dhcp_client *sd_dhcp_client_unref(sd_dhcp_client *client) { free(client->req_opts); free(client->hostname); free(client->vendor_class_identifier); - free(client); - - return NULL; + return mfree(client); } int sd_dhcp_client_new(sd_dhcp_client **ret) { @@ -1897,6 +1885,7 @@ int sd_dhcp_client_new(sd_dhcp_client **ret) { client->fd = -1; client->attempt = 1; client->mtu = DHCP_DEFAULT_MIN_SIZE; + client->port = DHCP_PORT_CLIENT; client->req_opts_size = ELEMENTSOF(default_req_opts); client->req_opts = memdup(default_req_opts, client->req_opts_size); diff --git a/src/systemd/src/libsystemd-network/sd-dhcp-lease.c b/src/systemd/src/libsystemd-network/sd-dhcp-lease.c index b0f0a844..5a3bff2f 100644 --- a/src/systemd/src/libsystemd-network/sd-dhcp-lease.c +++ b/src/systemd/src/libsystemd-network/sd-dhcp-lease.c @@ -284,9 +284,7 @@ sd_dhcp_lease *sd_dhcp_lease_unref(sd_dhcp_lease *lease) { free(lease->static_route); free(lease->client_id); free(lease->vendor_specific); - free(lease); - - return NULL; + return mfree(lease); } static int lease_parse_u32(const uint8_t *option, size_t len, uint32_t *ret, uint32_t min) { @@ -387,6 +385,23 @@ static int lease_parse_domain(const uint8_t *option, size_t len, char **ret) { return 0; } +static void filter_bogus_addresses(struct in_addr *addresses, size_t *n) { + size_t i, j; + + /* Silently filter DNS/NTP servers supplied to us that do not make outside of the local scope. */ + + for (i = 0, j = 0; i < *n; i ++) { + + if (in4_addr_is_null(addresses+i) || + in4_addr_is_localhost(addresses+i)) + continue; + + addresses[j++] = addresses[i]; + } + + *n = j; +} + static int lease_parse_in_addrs(const uint8_t *option, size_t len, struct in_addr **ret, size_t *n_ret) { assert(option); assert(ret); @@ -408,6 +423,8 @@ static int lease_parse_in_addrs(const uint8_t *option, size_t len, struct in_add if (!addresses) return -ENOMEM; + filter_bogus_addresses(addresses, &n_addresses); + free(*ret); *ret = addresses; *n_ret = n_addresses; diff --git a/src/systemd/src/libsystemd-network/sd-dhcp6-client.c b/src/systemd/src/libsystemd-network/sd-dhcp6-client.c index a05bde63..4615cb40 100644 --- a/src/systemd/src/libsystemd-network/sd-dhcp6-client.c +++ b/src/systemd/src/libsystemd-network/sd-dhcp6-client.c @@ -1304,9 +1304,7 @@ sd_dhcp6_client *sd_dhcp6_client_unref(sd_dhcp6_client *client) { sd_dhcp6_client_detach_event(client); free(client->req_opts); - free(client); - - return NULL; + return mfree(client); } int sd_dhcp6_client_new(sd_dhcp6_client **ret) { diff --git a/src/systemd/src/libsystemd-network/sd-dhcp6-lease.c b/src/systemd/src/libsystemd-network/sd-dhcp6-lease.c index 0070a78f..5419048f 100644 --- a/src/systemd/src/libsystemd-network/sd-dhcp6-lease.c +++ b/src/systemd/src/libsystemd-network/sd-dhcp6-lease.c @@ -391,9 +391,7 @@ sd_dhcp6_lease *sd_dhcp6_lease_unref(sd_dhcp6_lease *lease) { free(lease->ntp); lease->ntp_fqdn = strv_free(lease->ntp_fqdn); - free(lease); - - return NULL; + return mfree(lease); } int dhcp6_lease_new(sd_dhcp6_lease **ret) { diff --git a/src/systemd/src/libsystemd-network/sd-ipv4acd.c b/src/systemd/src/libsystemd-network/sd-ipv4acd.c index 59830795..913c1adb 100644 --- a/src/systemd/src/libsystemd-network/sd-ipv4acd.c +++ b/src/systemd/src/libsystemd-network/sd-ipv4acd.c @@ -137,9 +137,7 @@ sd_ipv4acd *sd_ipv4acd_unref(sd_ipv4acd *acd) { ipv4acd_reset(acd); sd_ipv4acd_detach_event(acd); - free(acd); - - return NULL; + return mfree(acd); } int sd_ipv4acd_new(sd_ipv4acd **ret) { diff --git a/src/systemd/src/libsystemd-network/sd-ipv4ll.c b/src/systemd/src/libsystemd-network/sd-ipv4ll.c index dc2fa370..2420c99f 100644 --- a/src/systemd/src/libsystemd-network/sd-ipv4ll.c +++ b/src/systemd/src/libsystemd-network/sd-ipv4ll.c @@ -92,9 +92,7 @@ sd_ipv4ll *sd_ipv4ll_unref(sd_ipv4ll *ll) { return NULL; sd_ipv4acd_unref(ll->acd); - free(ll); - - return NULL; + return mfree(ll); } int sd_ipv4ll_new(sd_ipv4ll **ret) { diff --git a/src/systemd/src/libsystemd-network/sd-lldp.c b/src/systemd/src/libsystemd-network/sd-lldp.c index f1ae6dac..66c9780e 100644 --- a/src/systemd/src/libsystemd-network/sd-lldp.c +++ b/src/systemd/src/libsystemd-network/sd-lldp.c @@ -376,9 +376,7 @@ _public_ sd_lldp* sd_lldp_unref(sd_lldp *lldp) { hashmap_free(lldp->neighbor_by_id); prioq_free(lldp->neighbor_by_expiry); - free(lldp); - - return NULL; + return mfree(lldp); } _public_ int sd_lldp_new(sd_lldp **ret) { diff --git a/src/systemd/src/libsystemd/sd-event/sd-event.c b/src/systemd/src/libsystemd/sd-event/sd-event.c index 0d400661..a51ab9e6 100644 --- a/src/systemd/src/libsystemd/sd-event/sd-event.c +++ b/src/systemd/src/libsystemd/sd-event/sd-event.c @@ -1543,7 +1543,8 @@ _public_ int sd_event_source_get_priority(sd_event_source *s, int64_t *priority) assert_return(s, -EINVAL); assert_return(!event_pid_changed(s->event), -ECHILD); - return s->priority; + *priority = s->priority; + return 0; } _public_ int sd_event_source_set_priority(sd_event_source *s, int64_t priority) { diff --git a/src/systemd/src/libsystemd/sd-id128/id128-util.c b/src/systemd/src/libsystemd/sd-id128/id128-util.c index c16052d8..57525ddb 100644 --- a/src/systemd/src/libsystemd/sd-id128/id128-util.c +++ b/src/systemd/src/libsystemd/sd-id128/id128-util.c @@ -191,10 +191,23 @@ int id128_write_fd(int fd, Id128Format f, sd_id128_t id, bool do_sync) { int id128_write(const char *p, Id128Format f, sd_id128_t id, bool do_sync) { _cleanup_close_ int fd = -1; - fd = open(p, O_WRONLY|O_CREAT|O_CLOEXEC|O_NOCTTY, 0444); + fd = open(p, O_WRONLY|O_CREAT|O_CLOEXEC|O_NOCTTY|O_TRUNC, 0444); if (fd < 0) return -errno; return id128_write_fd(fd, f, id, do_sync); } + +void id128_hash_func(const void *p, struct siphash *state) { + siphash24_compress(p, 16, state); +} + +int id128_compare_func(const void *a, const void *b) { + return memcmp(a, b, 16); +} + +const struct hash_ops id128_hash_ops = { + .hash = id128_hash_func, + .compare = id128_compare_func, +}; #endif /* NM_IGNORED */ diff --git a/src/systemd/src/libsystemd/sd-id128/id128-util.h b/src/systemd/src/libsystemd/sd-id128/id128-util.h index 3ba59acb..6b3855ac 100644 --- a/src/systemd/src/libsystemd/sd-id128/id128-util.h +++ b/src/systemd/src/libsystemd/sd-id128/id128-util.h @@ -22,6 +22,8 @@ #include <stdbool.h> #include "sd-id128.h" + +#include "hash-funcs.h" #include "macro.h" char *id128_to_uuid_string(sd_id128_t id, char s[37]); @@ -43,3 +45,7 @@ int id128_read(const char *p, Id128Format f, sd_id128_t *ret); int id128_write_fd(int fd, Id128Format f, sd_id128_t id, bool do_sync); int id128_write(const char *p, Id128Format f, sd_id128_t id, bool do_sync); + +void id128_hash_func(const void *p, struct siphash *state); +int id128_compare_func(const void *a, const void *b) _pure_; +extern const struct hash_ops id128_hash_ops; diff --git a/src/systemd/src/libsystemd/sd-id128/sd-id128.c b/src/systemd/src/libsystemd/sd-id128/sd-id128.c index 9408c32b..9920bfdf 100644 --- a/src/systemd/src/libsystemd/sd-id128/sd-id128.c +++ b/src/systemd/src/libsystemd/sd-id128/sd-id128.c @@ -25,12 +25,16 @@ #include "sd-id128.h" +#include "alloc-util.h" #include "fd-util.h" #include "hexdecoct.h" #include "id128-util.h" #include "io-util.h" +#include "khash.h" #include "macro.h" +#include "missing.h" #include "random-util.h" +#include "user-util.h" #include "util.h" #if 0 /* NM_IGNORED */ @@ -134,6 +138,143 @@ _public_ int sd_id128_get_boot(sd_id128_t *ret) { } #if 0 /* NM_IGNORED */ +static int get_invocation_from_keyring(sd_id128_t *ret) { + + _cleanup_free_ char *description = NULL; + char *d, *p, *g, *u, *e; + unsigned long perms; + key_serial_t key; + size_t sz = 256; + uid_t uid; + gid_t gid; + int r, c; + +#define MAX_PERMS ((unsigned long) (KEY_POS_VIEW|KEY_POS_READ|KEY_POS_SEARCH| \ + KEY_USR_VIEW|KEY_USR_READ|KEY_USR_SEARCH)) + + assert(ret); + + key = request_key("user", "invocation_id", NULL, 0); + if (key == -1) { + /* Keyring support not available? No invocation key stored? */ + if (IN_SET(errno, ENOSYS, ENOKEY)) + return 0; + + return -errno; + } + + for (;;) { + description = new(char, sz); + if (!description) + return -ENOMEM; + + c = keyctl(KEYCTL_DESCRIBE, key, (unsigned long) description, sz, 0); + if (c < 0) + return -errno; + + if ((size_t) c <= sz) + break; + + sz = c; + free(description); + } + + /* The kernel returns a final NUL in the string, verify that. */ + assert(description[c-1] == 0); + + /* Chop off the final description string */ + d = strrchr(description, ';'); + if (!d) + return -EIO; + *d = 0; + + /* Look for the permissions */ + p = strrchr(description, ';'); + if (!p) + return -EIO; + + errno = 0; + perms = strtoul(p + 1, &e, 16); + if (errno > 0) + return -errno; + if (e == p + 1) /* Read at least one character */ + return -EIO; + if (e != d) /* Must reached the end */ + return -EIO; + + if ((perms & ~MAX_PERMS) != 0) + return -EPERM; + + *p = 0; + + /* Look for the group ID */ + g = strrchr(description, ';'); + if (!g) + return -EIO; + r = parse_gid(g + 1, &gid); + if (r < 0) + return r; + if (gid != 0) + return -EPERM; + *g = 0; + + /* Look for the user ID */ + u = strrchr(description, ';'); + if (!u) + return -EIO; + r = parse_uid(u + 1, &uid); + if (r < 0) + return r; + if (uid != 0) + return -EPERM; + + c = keyctl(KEYCTL_READ, key, (unsigned long) ret, sizeof(sd_id128_t), 0); + if (c < 0) + return -errno; + if (c != sizeof(sd_id128_t)) + return -EIO; + + return 1; +} + +_public_ int sd_id128_get_invocation(sd_id128_t *ret) { + static thread_local sd_id128_t saved_invocation_id = {}; + int r; + + assert_return(ret, -EINVAL); + + if (sd_id128_is_null(saved_invocation_id)) { + + /* We first try to read the invocation ID from the kernel keyring. This has the benefit that it is not + * fakeable by unprivileged code. If the information is not available in the keyring, we use + * $INVOCATION_ID but ignore the data if our process was called by less privileged code + * (i.e. secure_getenv() instead of getenv()). + * + * The kernel keyring is only relevant for system services (as for user services we don't store the + * invocation ID in the keyring, as there'd be no trust benefit in that). The environment variable is + * primarily relevant for user services, and sufficiently safe as no privilege boundary is involved. */ + + r = get_invocation_from_keyring(&saved_invocation_id); + if (r < 0) + return r; + + if (r == 0) { + const char *e; + + e = secure_getenv("INVOCATION_ID"); + if (!e) + return -ENXIO; + + r = sd_id128_from_string(e, &saved_invocation_id); + if (r < 0) + return r; + } + } + + *ret = saved_invocation_id; + return 0; +} + static sd_id128_t make_v4_uuid(sd_id128_t id) { /* Stolen from generate_random_uuid() of drivers/char/random.c * in the kernel sources */ @@ -164,4 +305,35 @@ _public_ int sd_id128_randomize(sd_id128_t *ret) { *ret = make_v4_uuid(t); return 0; } + +_public_ int sd_id128_get_machine_app_specific(sd_id128_t app_id, sd_id128_t *ret) { + _cleanup_(khash_unrefp) khash *h = NULL; + sd_id128_t m, result; + const void *p; + int r; + + assert_return(ret, -EINVAL); + + r = sd_id128_get_machine(&m); + if (r < 0) + return r; + + r = khash_new_with_key(&h, "hmac(sha256)", &m, sizeof(m)); + if (r < 0) + return r; + + r = khash_put(h, &app_id, sizeof(app_id)); + if (r < 0) + return r; + + r = khash_digest_data(h, &p); + if (r < 0) + return r; + + /* We chop off the trailing 16 bytes */ + memcpy(&result, p, MIN(khash_get_size(h), sizeof(result))); + + *ret = make_v4_uuid(result); + return 0; +} #endif /* NM_IGNORED */ diff --git a/src/systemd/src/shared/dns-domain.c b/src/systemd/src/shared/dns-domain.c index e147637b..5ed27191 100644 --- a/src/systemd/src/shared/dns-domain.c +++ b/src/systemd/src/shared/dns-domain.c @@ -133,6 +133,10 @@ int dns_label_unescape(const char **name, char *dest, size_t sz) { if (r == 0 && *n) return -EINVAL; + /* More than one trailing dot? */ + if (*n == '.') + return -EINVAL; + if (sz >= 1 && d) *d = 0; @@ -1077,7 +1081,7 @@ int dns_service_split(const char *joined, char **_name, char **_type, char **_do if (!name) return -ENOMEM; - type = strjoin(b, ".", c, NULL); + type = strjoin(b, ".", c); if (!type) return -ENOMEM; @@ -1091,7 +1095,7 @@ int dns_service_split(const char *joined, char **_name, char **_type, char **_do name = NULL; - type = strjoin(a, ".", b, NULL); + type = strjoin(a, ".", b); if (!type) return -ENOMEM; @@ -1325,4 +1329,16 @@ int dns_name_apply_idna(const char *name, char **ret) { return (int) n; } + +int dns_name_is_valid_or_address(const char *name) { + /* Returns > 0 if the specified name is either a valid IP address formatted as string or a valid DNS name */ + + if (isempty(name)) + return 0; + + if (in_addr_from_string_auto(name, NULL, NULL) >= 0) + return 1; + + return dns_name_is_valid(name); +} #endif /* NM_IGNORED */ diff --git a/src/systemd/src/shared/dns-domain.h b/src/systemd/src/shared/dns-domain.h index af780f0b..03f16036 100644 --- a/src/systemd/src/shared/dns-domain.h +++ b/src/systemd/src/shared/dns-domain.h @@ -107,3 +107,5 @@ int dns_name_equal_skip(const char *a, unsigned n_labels, const char *b); int dns_name_common_suffix(const char *a, const char *b, const char **ret); int dns_name_apply_idna(const char *name, char **ret); + +int dns_name_is_valid_or_address(const char *name); diff --git a/src/systemd/src/systemd/sd-dhcp-client.h b/src/systemd/src/systemd/sd-dhcp-client.h index 9a90c2ed..ffe7f836 100644 --- a/src/systemd/src/systemd/sd-dhcp-client.h +++ b/src/systemd/src/systemd/sd-dhcp-client.h @@ -126,6 +126,9 @@ int sd_dhcp_client_get_client_id( int sd_dhcp_client_set_mtu( sd_dhcp_client *client, uint32_t mtu); +int sd_dhcp_client_set_client_port( + sd_dhcp_client *client, + uint16_t port); int sd_dhcp_client_set_hostname( sd_dhcp_client *client, const char *hostname); diff --git a/src/systemd/src/systemd/sd-id128.h b/src/systemd/src/systemd/sd-id128.h index 4dff0b9b..6cc8e4ac 100644 --- a/src/systemd/src/systemd/sd-id128.h +++ b/src/systemd/src/systemd/sd-id128.h @@ -39,14 +39,14 @@ union sd_id128 { #define SD_ID128_STRING_MAX 33 char *sd_id128_to_string(sd_id128_t id, char s[SD_ID128_STRING_MAX]); - int sd_id128_from_string(const char *s, sd_id128_t *ret); int sd_id128_randomize(sd_id128_t *ret); int sd_id128_get_machine(sd_id128_t *ret); - +int sd_id128_get_machine_app_specific(sd_id128_t app_id, sd_id128_t *ret); int sd_id128_get_boot(sd_id128_t *ret); +int sd_id128_get_invocation(sd_id128_t *ret); #define SD_ID128_MAKE(v0, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15) \ ((const sd_id128_t) { .bytes = { 0x##v0, 0x##v1, 0x##v2, 0x##v3, 0x##v4, 0x##v5, 0x##v6, 0x##v7, \ |