systemd: merge branch systemd into master

This commit is contained in:
Thomas Haller 2017-01-04 15:50:30 +01:00
commit a8afbb7299
27 changed files with 434 additions and 155 deletions

View file

@ -1056,6 +1056,7 @@ src_libsystemd_nm_la_SOURCES = \
src/systemd/sd-adapt/dirent-util.h \
src/systemd/sd-adapt/format-util.h \
src/systemd/sd-adapt/gunicode.h \
src/systemd/sd-adapt/khash.h \
src/systemd/sd-adapt/libudev.h \
src/systemd/sd-adapt/missing.h \
src/systemd/sd-adapt/mkdir.h \

View file

@ -0,0 +1,3 @@
#pragma once
/* dummy header */

View file

@ -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;
}

View file

@ -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;

View file

@ -1416,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 */

View file

@ -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);

View file

@ -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))
@ -605,10 +596,11 @@ int inotify_add_watch_fd(int fd, int what, uint32_t mask) {
return r;
}
int chase_symlinks(const char *path, const char *_root, char **ret) {
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;
@ -617,26 +609,39 @@ int chase_symlinks(const char *path, const char *_root, char **ret) {
/* 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" matters only if we encounter an absolute symlink, it's unused otherwise. Most importantly
* this means the path parameter passed in is not prefixed by it.
* 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. */
* 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;
if (_root) {
r = path_make_absolute_cwd(_root, &root);
if (r < 0)
return r;
}
fd = open("/", O_CLOEXEC|O_NOFOLLOW|O_PATH);
if (fd < 0)
return -errno;
@ -672,18 +677,20 @@ int chase_symlinks(const char *path, const char *_root, char **ret) {
_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, "/"))
return -EINVAL;
continue;
parent = dirname_malloc(done);
if (!parent)
return -ENOMEM;
/* Don't allow this to leave the root dir */
/* Don't allow this to leave the root dir. */
if (root &&
path_startswith(done, root) &&
!path_startswith(parent, root))
return -EINVAL;
continue;
free_and_replace(done, parent);
@ -699,8 +706,25 @@ int chase_symlinks(const char *path, const char *_root, char **ret) {
/* Otherwise let's see what this is. */
child = openat(fd, first + n, O_CLOEXEC|O_NOFOLLOW|O_PATH);
if (child < 0)
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;
@ -785,6 +809,6 @@ int chase_symlinks(const char *path, const char *_root, char **ret) {
*ret = done;
done = NULL;
return 0;
return exists;
}
#endif /* NM_IGNORED */

View file

@ -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);
@ -78,4 +78,16 @@ union inotify_event_buffer {
int inotify_add_watch_fd(int fd, int what, uint32_t mask);
int chase_symlinks(const char *path, const char *_root, char **ret);
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);

View file

@ -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;
}

View file

@ -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);

View file

@ -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 */

View file

@ -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);

View file

@ -223,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;
@ -236,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;
@ -254,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, "/"))
@ -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);

View file

@ -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);

View file

@ -888,6 +888,7 @@ static char* extract_multiplier(char *p, usec_t *multiplier) {
{ "y", USEC_PER_YEAR },
{ "usec", 1ULL },
{ "us", 1ULL },
{ "µs", 1ULL },
};
unsigned i;
@ -1021,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 */

View file

@ -20,7 +20,6 @@
#include "nm-sd-adapt.h"
#include <alloca.h>
#include <dirent.h>
#include <errno.h>
#include <fcntl.h>
#include <sched.h>
@ -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)

View file

@ -30,11 +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,
uint16_t 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);
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,

View file

@ -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>
@ -158,13 +159,14 @@ int dhcp_network_bind_raw_socket(int ifindex, union sockaddr_union *link,
bcast_addr, &eth_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);
@ -179,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)
@ -187,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)

View file

@ -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;

View file

@ -390,45 +390,23 @@ 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;
free(client->vendor_class_identifier);
client->vendor_class_identifier = new_vci;
return 0;
return free_and_strdup(&client->vendor_class_identifier, vci);
}
int sd_dhcp_client_set_client_port(
@ -1572,7 +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, client->port);
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;

View file

@ -385,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);
@ -406,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;

View file

@ -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) {

View file

@ -191,7 +191,7 @@ 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;

View file

@ -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,105 @@ _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;
@ -141,15 +244,31 @@ _public_ int sd_id128_get_invocation(sd_id128_t *ret) {
assert_return(ret, -EINVAL);
if (sd_id128_is_null(saved_invocation_id)) {
const char *e;
e = secure_getenv("INVOCATION_ID");
if (!e)
return -ENXIO;
/* 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 = sd_id128_from_string(e, &saved_invocation_id);
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;
@ -186,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 */

View file

@ -1329,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 */

View file

@ -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);

View file

@ -39,12 +39,12 @@ 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);