diff options
author | Thomas Haller <thaller@redhat.com> | 2014-11-12 19:14:23 +0100 |
---|---|---|
committer | Thomas Haller <thaller@redhat.com> | 2014-11-12 19:14:23 +0100 |
commit | 5913ddec8bc657161dd6156c1092595b12db378a (patch) | |
tree | a79713d2be36de89113ba56612b0c43921ce595d | |
parent | dd9bb5f376e1367a54b307c26bf4d888976c2d20 (diff) | |
parent | 37f000c3a859da646f456d56c280bfa2ceff6183 (diff) | |
download | NetworkManager-th/systemd-dhcp.tar.gz |
dhcp: merge branch 'systemd-dhcp'th/systemd-dhcp
21 files changed, 409 insertions, 331 deletions
diff --git a/configure.ac b/configure.ac index b5dbc0d250..108ca6e512 100644 --- a/configure.ac +++ b/configure.ac @@ -145,6 +145,17 @@ if ! test x"$ac_distver" = x""; then AC_DEFINE_UNQUOTED(NM_DIST_VERSION, "$ac_distver", [Define the distribution version string]) fi +AC_CHECK_DECLS([getrandom], + [], [], [[ +#include <sys/types.h> +#include <unistd.h> +#include <sys/mount.h> +#include <fcntl.h> +#include <sched.h> +#include <linux/loop.h> +#include <linux/random.h> +]]) + dnl dnl Default to using WEXT but allow it to be disabled dnl diff --git a/src/Makefile.am b/src/Makefile.am index eb5c64c089..925b0851ce 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -99,6 +99,7 @@ libsystemd_dhcp_la_SOURCES = \ dhcp-manager/systemd-dhcp/src/shared/fileio.c \ dhcp-manager/systemd-dhcp/src/shared/strv.h \ dhcp-manager/systemd-dhcp/src/shared/strv.c \ + dhcp-manager/systemd-dhcp/src/shared/unaligned.h \ dhcp-manager/systemd-dhcp/src/shared/utf8.h \ dhcp-manager/systemd-dhcp/src/shared/utf8.c \ dhcp-manager/systemd-dhcp/src/systemd/sd-dhcp-lease.h \ diff --git a/src/dhcp-manager/systemd-dhcp/nm-sd-adapt.c b/src/dhcp-manager/systemd-dhcp/nm-sd-adapt.c index dbc922e9eb..8ec8c5a97a 100644 --- a/src/dhcp-manager/systemd-dhcp/nm-sd-adapt.c +++ b/src/dhcp-manager/systemd-dhcp/nm-sd-adapt.c @@ -67,12 +67,12 @@ sd_event_source_unref (sd_event_source *s) } int -sd_event_source_set_name(sd_event_source *s, const char *name) +sd_event_source_set_description(sd_event_source *s, const char *description) { if (!s) return -EINVAL; - g_source_set_name_by_id (s->id, name); + g_source_set_name_by_id (s->id, description); return 0; } diff --git a/src/dhcp-manager/systemd-dhcp/nm-sd-adapt.h b/src/dhcp-manager/systemd-dhcp/nm-sd-adapt.h index 5bd1f81f8b..5ead01a3f9 100644 --- a/src/dhcp-manager/systemd-dhcp/nm-sd-adapt.h +++ b/src/dhcp-manager/systemd-dhcp/nm-sd-adapt.h @@ -105,5 +105,24 @@ static inline pid_t gettid(void) { return (pid_t) syscall(SYS_gettid); } +#ifndef GRND_NONBLOCK +#define GRND_NONBLOCK 0x0001 +#endif + +#ifndef __NR_getrandom +# if defined __x86_64__ +# define __NR_getrandom 318 +# else +# warning "__NR_getrandom unknown for your architecture" +# define __NR_getrandom 0xffffffff +# endif +#endif + +#if !HAVE_DECL_GETRANDOM +static inline int getrandom(void *buffer, size_t count, unsigned flags) { + return syscall(__NR_getrandom, buffer, count, flags); +} +#endif + #endif /* NM_SD_ADAPT_H */ diff --git a/src/dhcp-manager/systemd-dhcp/src/libsystemd-network/dhcp-lease-internal.h b/src/dhcp-manager/systemd-dhcp/src/libsystemd-network/dhcp-lease-internal.h index 375ded31a5..9e184ac4b5 100644 --- a/src/dhcp-manager/systemd-dhcp/src/libsystemd-network/dhcp-lease-internal.h +++ b/src/dhcp-manager/systemd-dhcp/src/libsystemd-network/dhcp-lease-internal.h @@ -35,7 +35,7 @@ struct sd_dhcp_route { struct in_addr dst_addr; struct in_addr gw_addr; - uint8_t dst_prefixlen; + unsigned char dst_prefixlen; }; struct sd_dhcp_lease { diff --git a/src/dhcp-manager/systemd-dhcp/src/libsystemd-network/dhcp6-option.c b/src/dhcp-manager/systemd-dhcp/src/libsystemd-network/dhcp6-option.c index c18fb2a660..10872a3159 100644 --- a/src/dhcp-manager/systemd-dhcp/src/libsystemd-network/dhcp6-option.c +++ b/src/dhcp-manager/systemd-dhcp/src/libsystemd-network/dhcp6-option.c @@ -26,31 +26,37 @@ #include <string.h> #include "sparse-endian.h" +#include "unaligned.h" #include "util.h" #include "dhcp6-internal.h" #include "dhcp6-protocol.h" -#define DHCP6_OPTION_HDR_LEN 4 #define DHCP6_OPTION_IA_NA_LEN 12 #define DHCP6_OPTION_IA_TA_LEN 4 +typedef struct DHCP6Option { + be16_t code; + be16_t len; + uint8_t data[]; +} _packed_ DHCP6Option; + static int option_append_hdr(uint8_t **buf, size_t *buflen, uint16_t optcode, size_t optlen) { + DHCP6Option *option = (DHCP6Option*) *buf; + assert_return(buf, -EINVAL); assert_return(*buf, -EINVAL); assert_return(buflen, -EINVAL); - if (optlen > 0xffff || *buflen < optlen + DHCP6_OPTION_HDR_LEN) + if (optlen > 0xffff || *buflen < optlen + sizeof(DHCP6Option)) return -ENOBUFS; - (*buf)[0] = optcode >> 8; - (*buf)[1] = optcode & 0xff; - (*buf)[2] = optlen >> 8; - (*buf)[3] = optlen & 0xff; + option->code = htobe16(optcode); + option->len = htobe16(optlen); - *buf += DHCP6_OPTION_HDR_LEN; - *buflen -= DHCP6_OPTION_HDR_LEN; + *buf += sizeof(DHCP6Option); + *buflen -= sizeof(DHCP6Option); return 0; } @@ -102,8 +108,8 @@ int dhcp6_option_append_ia(uint8_t **buf, size_t *buflen, DHCP6IA *ia) { ia_hdr = *buf; ia_buflen = *buflen; - *buf += DHCP6_OPTION_HDR_LEN; - *buflen -= DHCP6_OPTION_HDR_LEN; + *buf += sizeof(DHCP6Option); + *buflen -= sizeof(DHCP6Option); memcpy(*buf, &ia->id, len); @@ -121,7 +127,7 @@ int dhcp6_option_append_ia(uint8_t **buf, size_t *buflen, DHCP6IA *ia) { *buf += sizeof(addr->iaaddr); *buflen -= sizeof(addr->iaaddr); - ia_addrlen += DHCP6_OPTION_HDR_LEN + sizeof(addr->iaaddr); + ia_addrlen += sizeof(DHCP6Option) + sizeof(addr->iaaddr); } r = option_append_hdr(&ia_hdr, &ia_buflen, ia->type, len + ia_addrlen); @@ -132,23 +138,23 @@ int dhcp6_option_append_ia(uint8_t **buf, size_t *buflen, DHCP6IA *ia) { } -static int option_parse_hdr(uint8_t **buf, size_t *buflen, uint16_t *opt, - size_t *optlen) { +static int option_parse_hdr(uint8_t **buf, size_t *buflen, uint16_t *optcode, size_t *optlen) { + DHCP6Option *option = (DHCP6Option*) *buf; uint16_t len; assert_return(buf, -EINVAL); - assert_return(opt, -EINVAL); + assert_return(optcode, -EINVAL); assert_return(optlen, -EINVAL); - if (*buflen < 4) + if (*buflen < sizeof(DHCP6Option)) return -ENOMSG; - len = (*buf)[2] << 8 | (*buf)[3]; + len = be16toh(option->len); if (len > *buflen) return -ENOMSG; - *opt = (*buf)[0] << 8 | (*buf)[1]; + *optcode = be16toh(option->code); *optlen = len; *buf += 4; @@ -192,7 +198,7 @@ int dhcp6_option_parse_ia(uint8_t **buf, size_t *buflen, uint16_t iatype, switch (iatype) { case DHCP6_OPTION_IA_NA: - if (*buflen < DHCP6_OPTION_IA_NA_LEN + DHCP6_OPTION_HDR_LEN + + if (*buflen < DHCP6_OPTION_IA_NA_LEN + sizeof(DHCP6Option) + sizeof(addr->iaaddr)) { r = -ENOBUFS; goto error; @@ -214,7 +220,7 @@ int dhcp6_option_parse_ia(uint8_t **buf, size_t *buflen, uint16_t iatype, break; case DHCP6_OPTION_IA_TA: - if (*buflen < DHCP6_OPTION_IA_TA_LEN + DHCP6_OPTION_HDR_LEN + + if (*buflen < DHCP6_OPTION_IA_TA_LEN + sizeof(DHCP6Option) + sizeof(addr->iaaddr)) { r = -ENOBUFS; goto error; diff --git a/src/dhcp-manager/systemd-dhcp/src/libsystemd-network/network-internal.c b/src/dhcp-manager/systemd-dhcp/src/libsystemd-network/network-internal.c index f870e3bb42..8418f5e429 100644 --- a/src/dhcp-manager/systemd-dhcp/src/libsystemd-network/network-internal.c +++ b/src/dhcp-manager/systemd-dhcp/src/libsystemd-network/network-internal.c @@ -107,16 +107,16 @@ bool net_match_config(const struct ether_addr *match_mac, const char *dev_type, const char *dev_name) { - if (match_host && !condition_test_host(match_host)) + if (match_host && !condition_test(match_host)) return 0; - if (match_virt && !condition_test_virtualization(match_virt)) + if (match_virt && !condition_test(match_virt)) return 0; - if (match_kernel && !condition_test_kernel_command_line(match_kernel)) + if (match_kernel && !condition_test(match_kernel)) return 0; - if (match_arch && !condition_test_architecture(match_arch)) + if (match_arch && !condition_test(match_arch)) return 0; if (match_mac && (!dev_mac || memcmp(match_mac, dev_mac, ETH_ALEN))) diff --git a/src/dhcp-manager/systemd-dhcp/src/libsystemd-network/network-internal.h b/src/dhcp-manager/systemd-dhcp/src/libsystemd-network/network-internal.h index f4ff1dd4e8..f87c863d91 100644 --- a/src/dhcp-manager/systemd-dhcp/src/libsystemd-network/network-internal.h +++ b/src/dhcp-manager/systemd-dhcp/src/libsystemd-network/network-internal.h @@ -29,7 +29,7 @@ #if 0 /* NM_IGNORED */ #include "udev.h" -#include "condition-util.h" +#include "condition.h" bool net_match_config(const struct ether_addr *match_mac, const char *match_path, diff --git a/src/dhcp-manager/systemd-dhcp/src/libsystemd-network/sd-dhcp-client.c b/src/dhcp-manager/systemd-dhcp/src/libsystemd-network/sd-dhcp-client.c index 18c23f15c1..1cb698dc4d 100644 --- a/src/dhcp-manager/systemd-dhcp/src/libsystemd-network/sd-dhcp-client.c +++ b/src/dhcp-manager/systemd-dhcp/src/libsystemd-network/sd-dhcp-client.c @@ -812,8 +812,7 @@ static int client_timeout_resend(sd_event_source *s, uint64_t usec, if (r < 0) goto error; - r = sd_event_source_set_name(client->timeout_resend, - "dhcp4-resend-timer"); + r = sd_event_source_set_description(client->timeout_resend, "dhcp4-resend-timer"); if (r < 0) goto error; @@ -890,8 +889,7 @@ static int client_initialize_io_events(sd_dhcp_client *client, if (r < 0) goto error; - r = sd_event_source_set_name(client->receive_message, - "dhcp4-receive-message"); + r = sd_event_source_set_description(client->receive_message, "dhcp4-receive-message"); if (r < 0) goto error; @@ -921,8 +919,7 @@ static int client_initialize_time_events(sd_dhcp_client *client) { r = sd_event_source_set_priority(client->timeout_resend, client->event_priority); - r = sd_event_source_set_name(client->timeout_resend, - "dhcp4-resend-timer"); + r = sd_event_source_set_description(client->timeout_resend, "dhcp4-resend-timer"); if (r < 0) goto error; @@ -1252,8 +1249,7 @@ static int client_set_lease_timeouts(sd_dhcp_client *client) { if (r < 0) return r; - r = sd_event_source_set_name(client->timeout_expire, - "dhcp4-lifetime"); + r = sd_event_source_set_description(client->timeout_expire, "dhcp4-lifetime"); if (r < 0) return r; @@ -1280,8 +1276,7 @@ static int client_set_lease_timeouts(sd_dhcp_client *client) { if (r < 0) return r; - r = sd_event_source_set_name(client->timeout_t2, - "dhcp4-t2-timeout"); + r = sd_event_source_set_description(client->timeout_t2, "dhcp4-t2-timeout"); if (r < 0) return r; @@ -1307,8 +1302,7 @@ static int client_set_lease_timeouts(sd_dhcp_client *client) { if (r < 0) return r; - r = sd_event_source_set_name(client->timeout_t1, - "dhcp4-t1-timer"); + r = sd_event_source_set_description(client->timeout_t1, "dhcp4-t1-timer"); if (r < 0) return r; @@ -1353,8 +1347,7 @@ static int client_handle_message(sd_dhcp_client *client, DHCPMessage *message, if (r < 0) goto error; - r = sd_event_source_set_name(client->timeout_resend, - "dhcp4-resend-timer"); + r = sd_event_source_set_description(client->timeout_resend, "dhcp4-resend-timer"); if (r < 0) goto error; } else if (r == -ENOMSG) diff --git a/src/dhcp-manager/systemd-dhcp/src/libsystemd-network/sd-dhcp-lease.c b/src/dhcp-manager/systemd-dhcp/src/libsystemd-network/sd-dhcp-lease.c index e61ae051f3..e6c26cc0a8 100644 --- a/src/dhcp-manager/systemd-dhcp/src/libsystemd-network/sd-dhcp-lease.c +++ b/src/dhcp-manager/systemd-dhcp/src/libsystemd-network/sd-dhcp-lease.c @@ -34,6 +34,7 @@ #include "mkdir.h" #endif #include "fileio.h" +#include "unaligned.h" #include "in-addr-util.h" #include "dhcp-protocol.h" @@ -210,14 +211,11 @@ sd_dhcp_lease *sd_dhcp_lease_unref(sd_dhcp_lease *lease) { } static void lease_parse_u32(const uint8_t *option, size_t len, uint32_t *ret, uint32_t min) { - be32_t val; - assert(option); assert(ret); if (len == 4) { - memcpy(&val, option, 4); - *ret = be32toh(val); + *ret = unaligned_read_be32((be32_t*) option); if (*ret < min) *ret = min; @@ -229,14 +227,11 @@ static void lease_parse_s32(const uint8_t *option, size_t len, int32_t *ret) { } static void lease_parse_u16(const uint8_t *option, size_t len, uint16_t *ret, uint16_t min) { - be16_t val; - assert(option); assert(ret); if (len == 2) { - memcpy(&val, option, 2); - *ret = be16toh(val); + *ret = unaligned_read_be16((be16_t*) option); if (*ret < min) *ret = min; @@ -320,23 +315,6 @@ static int lease_parse_in_addrs_pairs(const uint8_t *option, size_t len, struct return lease_parse_in_addrs_aux(option, len, ret, ret_size, 2); } -static int class_prefixlen(uint8_t msb_octet, uint8_t *ret) { - if (msb_octet < 128) - /* Class A */ - *ret = 8; - else if (msb_octet < 192) - /* Class B */ - *ret = 16; - else if (msb_octet < 224) - /* Class C */ - *ret = 24; - else - /* Class D or E -- no subnet mask */ - return -ERANGE; - - return 0; -} - static int lease_parse_routes(const uint8_t *option, size_t len, struct sd_dhcp_route **routes, size_t *routes_size, size_t *routes_allocated) { @@ -358,8 +336,10 @@ static int lease_parse_routes(const uint8_t *option, size_t len, struct sd_dhcp_ while (len >= 8) { struct sd_dhcp_route *route = *routes + *routes_size; + int r; - if (class_prefixlen(*option, &route->dst_prefixlen) < 0) { + r = in_addr_default_prefixlen((struct in_addr*) option, &route->dst_prefixlen); + if (r < 0) { log_error("Failed to determine destination prefix length from class based IP, ignoring"); continue; } diff --git a/src/dhcp-manager/systemd-dhcp/src/libsystemd-network/sd-dhcp6-client.c b/src/dhcp-manager/systemd-dhcp/src/libsystemd-network/sd-dhcp6-client.c index f9a9d5e9e5..20ba0db2cc 100644 --- a/src/dhcp-manager/systemd-dhcp/src/libsystemd-network/sd-dhcp6-client.c +++ b/src/dhcp-manager/systemd-dhcp/src/libsystemd-network/sd-dhcp6-client.c @@ -595,8 +595,7 @@ static int client_timeout_resend(sd_event_source *s, uint64_t usec, if (r < 0) goto error; - r = sd_event_source_set_name(client->timeout_resend, - "dhcp6-resend-timer"); + r = sd_event_source_set_description(client->timeout_resend, "dhcp6-resend-timer"); if (r < 0) goto error; @@ -619,8 +618,7 @@ static int client_timeout_resend(sd_event_source *s, uint64_t usec, if (r < 0) goto error; - r = sd_event_source_set_name(client->timeout_resend_expire, - "dhcp6-resend-expire-timer"); + r = sd_event_source_set_description(client->timeout_resend_expire, "dhcp6-resend-expire-timer"); if (r < 0) goto error; } @@ -992,8 +990,7 @@ static int client_start(sd_dhcp6_client *client, enum DHCP6State state) if (r < 0) return r; - r = sd_event_source_set_name(client->receive_message, - "dhcp6-receive-message"); + r = sd_event_source_set_description(client->receive_message, "dhcp6-receive-message"); if (r < 0) return r; @@ -1041,8 +1038,7 @@ static int client_start(sd_dhcp6_client *client, enum DHCP6State state) if (r < 0) return r; - r = sd_event_source_set_name(client->lease->ia.timeout_t1, - "dhcp6-t1-timeout"); + r = sd_event_source_set_description(client->lease->ia.timeout_t1, "dhcp6-t1-timeout"); if (r < 0) return r; @@ -1066,8 +1062,7 @@ static int client_start(sd_dhcp6_client *client, enum DHCP6State state) if (r < 0) return r; - r = sd_event_source_set_name(client->lease->ia.timeout_t2, - "dhcp6-t2-timeout"); + r = sd_event_source_set_description(client->lease->ia.timeout_t2, "dhcp6-t2-timeout"); if (r < 0) return r; @@ -1090,8 +1085,7 @@ static int client_start(sd_dhcp6_client *client, enum DHCP6State state) if (r < 0) return r; - r = sd_event_source_set_name(client->timeout_resend, - "dhcp6-resend-timeout"); + r = sd_event_source_set_description(client->timeout_resend, "dhcp6-resend-timeout"); if (r < 0) return r; diff --git a/src/dhcp-manager/systemd-dhcp/src/shared/fileio.c b/src/dhcp-manager/systemd-dhcp/src/shared/fileio.c index ffdc122110..39a3bc1732 100644 --- a/src/dhcp-manager/systemd-dhcp/src/shared/fileio.c +++ b/src/dhcp-manager/systemd-dhcp/src/shared/fileio.c @@ -20,12 +20,12 @@ ***/ #include <unistd.h> -#include <sys/sendfile.h> -#include "fileio.h" + #include "util.h" #include "strv.h" #include "utf8.h" #include "ctype.h" +#include "fileio.h" int write_string_stream(FILE *f, const char *line) { assert(f); @@ -66,7 +66,7 @@ int write_string_file_no_create(const char *fn, const char *line) { assert(line); /* We manually build our own version of fopen(..., "we") that - * without O_CREAT */ + * works without O_CREAT */ fd = open(fn, O_WRONLY|O_CLOEXEC|O_NOCTTY); if (fd < 0) return -errno; @@ -94,20 +94,10 @@ int write_string_file_atomic(const char *fn, const char *line) { fchmod_umask(fileno(f), 0644); - errno = 0; - fputs(line, f); - if (!endswith(line, "\n")) - fputc('\n', f); - - fflush(f); - - if (ferror(f)) - r = errno ? -errno : -EIO; - else { + r = write_string_stream(f, line); + if (r >= 0) { if (rename(p, fn) < 0) r = -errno; - else - r = 0; } if (r < 0) @@ -144,77 +134,6 @@ int read_one_line_file(const char *fn, char **line) { return 0; } -ssize_t sendfile_full(int out_fd, const char *fn) { - _cleanup_fclose_ FILE *f = NULL; - struct stat st; - int r; - ssize_t s; - - size_t n, l; - _cleanup_free_ char *buf = NULL; - - assert(out_fd > 0); - assert(fn); - - f = fopen(fn, "re"); - if (!f) - return -errno; - - r = fstat(fileno(f), &st); - if (r < 0) - return -errno; - - s = sendfile(out_fd, fileno(f), NULL, st.st_size); - if (s < 0) - if (errno == EINVAL || errno == ENOSYS) { - /* continue below */ - } else - return -errno; - else - return s; - - /* sendfile() failed, fall back to read/write */ - - /* Safety check */ - if (st.st_size > 4*1024*1024) - return -E2BIG; - - n = st.st_size > 0 ? st.st_size : LINE_MAX; - l = 0; - - while (true) { - char *t; - size_t k; - - t = realloc(buf, n); - if (!t) - return -ENOMEM; - - buf = t; - k = fread(buf + l, 1, n - l, f); - - if (k <= 0) { - if (ferror(f)) - return -errno; - - break; - } - - l += k; - n *= 2; - - /* Safety check */ - if (n > 4*1024*1024) - return -E2BIG; - } - - r = write(out_fd, buf, l); - if (r < 0) - return -errno; - - return (ssize_t) l; -} - int read_full_stream(FILE *f, char **contents, size_t *size) { size_t n, l; _cleanup_free_ char *buf = NULL; diff --git a/src/dhcp-manager/systemd-dhcp/src/shared/fileio.h b/src/dhcp-manager/systemd-dhcp/src/shared/fileio.h index c256915799..5ae51c1e28 100644 --- a/src/dhcp-manager/systemd-dhcp/src/shared/fileio.h +++ b/src/dhcp-manager/systemd-dhcp/src/shared/fileio.h @@ -33,7 +33,6 @@ int write_string_file_atomic(const char *fn, const char *line); int read_one_line_file(const char *fn, char **line); int read_full_file(const char *fn, char **contents, size_t *size); int read_full_stream(FILE *f, char **contents, size_t *size); -ssize_t sendfile_full(int out_fd, const char *fn); int parse_env_file(const char *fname, const char *separator, ...) _sentinel_; int load_env_file(FILE *f, const char *fname, const char *separator, char ***l); diff --git a/src/dhcp-manager/systemd-dhcp/src/shared/in-addr-util.c b/src/dhcp-manager/systemd-dhcp/src/shared/in-addr-util.c index 5fbee6caf2..9dc9ec82b4 100644 --- a/src/dhcp-manager/systemd-dhcp/src/shared/in-addr-util.c +++ b/src/dhcp-manager/systemd-dhcp/src/shared/in-addr-util.c @@ -250,21 +250,20 @@ unsigned in_addr_netmask_to_prefixlen(const struct in_addr *addr) { } int in_addr_default_prefixlen(const struct in_addr *addr, unsigned char *prefixlen) { - uint32_t address; + uint8_t msb_octet = *(uint8_t*) addr; + + /* addr may not be aligned, so make sure we only access it byte-wise */ assert(addr); - assert(addr->s_addr != INADDR_ANY); assert(prefixlen); - address = be32toh(addr->s_addr); - - if ((address >> 31) == 0x0) + if (msb_octet < 128) /* class A, leading bits: 0 */ *prefixlen = 8; - else if ((address >> 30) == 0x2) + else if (msb_octet < 192) /* class B, leading bits 10 */ *prefixlen = 16; - else if ((address >> 29) == 0x6) + else if (msb_octet < 224) /* class C, leading bits 110 */ *prefixlen = 24; else diff --git a/src/dhcp-manager/systemd-dhcp/src/shared/strv.c b/src/dhcp-manager/systemd-dhcp/src/shared/strv.c index 9d1e6b22ea..5eceb76123 100644 --- a/src/dhcp-manager/systemd-dhcp/src/shared/strv.c +++ b/src/dhcp-manager/systemd-dhcp/src/shared/strv.c @@ -250,40 +250,6 @@ char **strv_split(const char *s, const char *separator) { return r; } -int strv_split_quoted(char ***t, const char *s) { - const char *word, *state; - size_t l; - unsigned n, i; - char **r; - - assert(s); - - n = 0; - FOREACH_WORD_QUOTED(word, l, s, state) - n++; - if (!isempty(state)) - /* bad syntax */ - return -EINVAL; - - r = new(char*, n+1); - if (!r) - return -ENOMEM; - - i = 0; - FOREACH_WORD_QUOTED(word, l, s, state) { - r[i] = cunescape_length(word, l); - if (!r[i]) { - strv_free(r); - return -ENOMEM; - } - i++; - } - - r[i] = NULL; - *t = r; - return 0; -} - char **strv_split_newlines(const char *s) { char **l; unsigned n; @@ -309,6 +275,43 @@ char **strv_split_newlines(const char *s) { return l; } +#if 0 /* NM_IGNORED */ +int strv_split_quoted(char ***t, const char *s, bool relax) { + size_t n = 0, allocated = 0; + _cleanup_strv_free_ char **l = NULL; + int r; + + assert(t); + assert(s); + + for (;;) { + _cleanup_free_ char *word = NULL; + + r = unquote_first_word(&s, &word, relax); + if (r < 0) + return r; + if (r == 0) + break; + + if (!GREEDY_REALLOC(l, allocated, n + 2)) + return -ENOMEM; + + l[n++] = word; + word = NULL; + + l[n] = NULL; + } + + if (!l) + l = new0(char*, 1); + + *t = l; + l = NULL; + + return 0; +} +#endif + char *strv_join(char **l, const char *separator) { char *r, *e; char **s; diff --git a/src/dhcp-manager/systemd-dhcp/src/shared/strv.h b/src/dhcp-manager/systemd-dhcp/src/shared/strv.h index 9c9633c515..47618bd26c 100644 --- a/src/dhcp-manager/systemd-dhcp/src/shared/strv.h +++ b/src/dhcp-manager/systemd-dhcp/src/shared/strv.h @@ -63,9 +63,10 @@ static inline bool strv_isempty(char * const *l) { } char **strv_split(const char *s, const char *separator); -int strv_split_quoted(char ***t, const char *s); char **strv_split_newlines(const char *s); +int strv_split_quoted(char ***t, const char *s, bool relax); + char *strv_join(char **l, const char *separator); char *strv_join_quoted(char **l); diff --git a/src/dhcp-manager/systemd-dhcp/src/shared/unaligned.h b/src/dhcp-manager/systemd-dhcp/src/shared/unaligned.h new file mode 100644 index 0000000000..d6181dd9a9 --- /dev/null +++ b/src/dhcp-manager/systemd-dhcp/src/shared/unaligned.h @@ -0,0 +1,66 @@ +/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ + +#pragma once + +/*** + This file is part of systemd. + + Copyright 2014 Tom Gundersen + + systemd is free software; you can redistribute it and/or modify it + under the terms of the GNU Lesser General Public License as published by + the Free Software Foundation; either version 2.1 of the License, or + (at your option) any later version. + + systemd is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public License + along with systemd; If not, see <http://www.gnu.org/licenses/>. +***/ + +#include <stdint.h> + +static inline uint16_t unaligned_read_be16(const void *_u) { + const uint8_t *u = _u; + + return (((uint16_t) u[0]) << 8) | + ((uint16_t) u[1]); +} + +static inline uint32_t unaligned_read_be32(const void *_u) { + const uint8_t *u = _u; + + return (((uint32_t) unaligned_read_be16(u)) << 16) | + ((uint32_t) unaligned_read_be16(u + 2)); +} + +static inline uint64_t unaligned_read_be64(const void *_u) { + const uint8_t *u = _u; + + return (((uint64_t) unaligned_read_be32(u)) << 32) | + ((uint64_t) unaligned_read_be32(u + 4)); +} + +static inline void unaligned_write_be16(void *_u, uint16_t a) { + uint8_t *u = _u; + + u[0] = (uint8_t) (a >> 8); + u[1] = (uint8_t) a; +} + +static inline void unaligned_write_be32(void *_u, uint32_t a) { + uint8_t *u = _u; + + unaligned_write_be16(u, (uint16_t) (a >> 16)); + unaligned_write_be16(u + 2, (uint16_t) a); +} + +static inline void unaligned_write_be64(void *_u, uint64_t a) { + uint8_t *u = _u; + + unaligned_write_be32(u, (uint32_t) (a >> 32)); + unaligned_write_be32(u + 4, (uint32_t) a); +} diff --git a/src/dhcp-manager/systemd-dhcp/src/shared/utf8.c b/src/dhcp-manager/systemd-dhcp/src/shared/utf8.c index dd3adf0add..261f39db84 100644 --- a/src/dhcp-manager/systemd-dhcp/src/shared/utf8.c +++ b/src/dhcp-manager/systemd-dhcp/src/shared/utf8.c @@ -152,10 +152,12 @@ bool utf8_is_printable_newline(const char* str, size_t length, bool newline) { int encoded_len, val; encoded_len = utf8_encoded_valid_unichar((const char *) p); - val = utf8_encoded_to_unichar((const char*) p); - if (encoded_len < 0 || - val < 0 || + (size_t) encoded_len > length) + return false; + + val = utf8_encoded_to_unichar((const char*) p); + if (val < 0 || is_unicode_control(val) || (!newline && val == '\n')) return false; diff --git a/src/dhcp-manager/systemd-dhcp/src/shared/util.c b/src/dhcp-manager/systemd-dhcp/src/shared/util.c index 56fea661ae..5248e1e518 100644 --- a/src/dhcp-manager/systemd-dhcp/src/shared/util.c +++ b/src/dhcp-manager/systemd-dhcp/src/shared/util.c @@ -708,7 +708,7 @@ int get_process_cmdline(pid_t pid, size_t max_length, bool comm_fallback, char * } /* Kernel threads have no argv[] */ - if (r == NULL || r[0] == 0) { + if (isempty(r)) { _cleanup_free_ char *t = NULL; int h; @@ -908,6 +908,28 @@ int readlink_malloc(const char *p, char **ret) { return readlinkat_malloc(AT_FDCWD, p, ret); } +int readlink_value(const char *p, char **ret) { + _cleanup_free_ char *link = NULL; + char *value; + int r; + + r = readlink_malloc(p, &link); + if (r < 0) + return r; + + value = basename(link); + if (!value) + return -ENOENT; + + value = strdup(value); + if (!value) + return -ENOMEM; + + *ret = value; + + return 0; +} + int readlink_and_make_absolute(const char *p, char **r) { _cleanup_free_ char *target = NULL; char *k; @@ -2490,14 +2512,53 @@ char* dirname_malloc(const char *path) { #endif int dev_urandom(void *p, size_t n) { - _cleanup_close_ int fd = -1; + static int have_syscall = -1; + int r, fd; ssize_t k; + /* Gathers some randomness from the kernel. This call will + * never block, and will always return some data from the + * kernel, regardless if the random pool is fully initialized + * or not. It thus makes no guarantee for the quality of the + * returned entropy, but is good enough for or usual usecases + * of seeding the hash functions for hashtable */ + + /* Use the getrandom() syscall unless we know we don't have + * it, or when the requested size is too large for it. */ + if (have_syscall != 0 || (size_t) (int) n != n) { + r = getrandom(p, n, GRND_NONBLOCK); + if (r == (int) n) { + have_syscall = true; + return 0; + } + + if (r < 0) { + if (errno == ENOSYS) + /* we lack the syscall, continue with + * reading from /dev/urandom */ + have_syscall = false; + else if (errno == EAGAIN) + /* not enough entropy for now. Let's + * remember to use the syscall the + * next time, again, but also read + * from /dev/urandom for now, which + * doesn't care about the current + * amount of entropy. */ + have_syscall = true; + else + return -errno; + } else + /* too short read? */ + return -EIO; + } + fd = open("/dev/urandom", O_RDONLY|O_CLOEXEC|O_NOCTTY); if (fd < 0) return errno == ENOENT ? -ENOSYS : -errno; k = loop_read(fd, p, n, true); + safe_close(fd); + if (k < 0) return (int) k; if ((size_t) k != n) @@ -2506,8 +2567,36 @@ int dev_urandom(void *p, size_t n) { return 0; } -void random_bytes(void *p, size_t n) { +void initialize_srand(void) { static bool srand_called = false; + unsigned x; +#ifdef HAVE_SYS_AUXV_H + void *auxv; +#endif + + if (srand_called) + return; + + x = 0; + +#ifdef HAVE_SYS_AUXV_H + /* The kernel provides us with a bit of entropy in auxv, so + * let's try to make use of that to seed the pseudo-random + * generator. It's better than nothing... */ + + auxv = (void*) getauxval(AT_RANDOM); + if (auxv) + x ^= *(unsigned*) auxv; +#endif + + x ^= (unsigned) now(CLOCK_REALTIME); + x ^= (unsigned) gettid(); + + srand(x); + srand_called = true; +} + +void random_bytes(void *p, size_t n) { uint8_t *q; int r; @@ -2518,28 +2607,7 @@ void random_bytes(void *p, size_t n) { /* If some idiot made /dev/urandom unavailable to us, he'll * get a PRNG instead. */ - if (!srand_called) { - unsigned x = 0; - -#ifdef HAVE_SYS_AUXV_H - /* The kernel provides us with a bit of entropy in - * auxv, so let's try to make use of that to seed the - * pseudo-random generator. It's better than - * nothing... */ - - void *auxv; - - auxv = (void*) getauxval(AT_RANDOM); - if (auxv) - x ^= *(unsigned*) auxv; -#endif - - x ^= (unsigned) now(CLOCK_REALTIME); - x ^= (unsigned) gettid(); - - srand(x); - srand_called = true; - } + initialize_srand(); for (q = p; q < (uint8_t*) p + n; q ++) *q = rand(); @@ -2762,7 +2830,7 @@ int get_ctty(pid_t pid, dev_t *_devnr, char **r) { if (k < 0) return k; - snprintf(fn, sizeof(fn), "/dev/char/%u:%u", major(devnr), minor(devnr)); + sprintf(fn, "/dev/char/%u:%u", major(devnr), minor(devnr)); k = readlink_malloc(fn, &s); if (k < 0) { @@ -2920,6 +2988,19 @@ int rm_rf_children(int fd, bool only_dirs, bool honour_sticky, struct stat *root return rm_rf_children_dangerous(fd, only_dirs, honour_sticky, root_dev); } +static int file_is_priv_sticky(const char *p) { + struct stat st; + + assert(p); + + if (lstat(p, &st) < 0) + return -errno; + + return + (st.st_uid == 0 || st.st_uid == getuid()) && + (st.st_mode & S_ISVTX); +} + static int rm_rf_internal(const char *path, bool only_dirs, bool delete_root, bool honour_sticky, bool dangerous) { int fd, r; struct statfs s; @@ -3158,7 +3239,8 @@ char *replace_env(const char *format, char **env) { case CURLY: if (*e == '{') { - if (!(k = strnappend(r, word, e-word-1))) + k = strnappend(r, word, e-word-1); + if (!k) goto fail; free(r); @@ -3168,7 +3250,8 @@ char *replace_env(const char *format, char **env) { state = VARIABLE; } else if (*e == '$') { - if (!(k = strnappend(r, word, e-word))) + k = strnappend(r, word, e-word); + if (!k) goto fail; free(r); @@ -3200,7 +3283,8 @@ char *replace_env(const char *format, char **env) { } } - if (!(k = strnappend(r, word, e-word))) + k = strnappend(r, word, e-word); + if (!k) goto fail; free(r); @@ -3211,6 +3295,7 @@ fail: return NULL; } +#if 0 /* NM_IGNORED */ char **replace_env_argv(char **argv, char **env) { char **ret, **i; unsigned k = 0, l = 0; @@ -3233,7 +3318,7 @@ char **replace_env_argv(char **argv, char **env) { if (e) { int r; - r = strv_split_quoted(&m, e); + r = strv_split_quoted(&m, e, true); if (r < 0) { ret[k] = NULL; strv_free(ret); @@ -3275,6 +3360,7 @@ char **replace_env_argv(char **argv, char **env) { ret[k] = NULL; return ret; } +#endif int fd_columns(int fd) { struct winsize ws = {}; @@ -3554,41 +3640,33 @@ char *unquote(const char *s, const char* quotes) { } char *normalize_env_assignment(const char *s) { - _cleanup_free_ char *name = NULL, *value = NULL, *p = NULL; - char *eq, *r; + _cleanup_free_ char *value = NULL; + const char *eq; + char *p, *name; eq = strchr(s, '='); if (!eq) { - char *t; + char *r, *t; r = strdup(s); if (!r) return NULL; t = strstrip(r); - if (t == r) - return r; + if (t != r) + memmove(r, t, strlen(t) + 1); - memmove(r, t, strlen(t) + 1); return r; } - name = strndup(s, eq - s); - if (!name) - return NULL; - - p = strdup(eq + 1); - if (!p) - return NULL; + name = strndupa(s, eq - s); + p = strdupa(eq + 1); value = unquote(strstrip(p), QUOTES); if (!value) return NULL; - if (asprintf(&r, "%s=%s", strstrip(name), value) < 0) - r = NULL; - - return r; + return strjoin(strstrip(name), "=", value, NULL); } int wait_for_terminate(pid_t pid, siginfo_t *status) { @@ -4811,19 +4889,6 @@ int block_get_whole_disk(dev_t d, dev_t *ret) { return -ENOENT; } -int file_is_priv_sticky(const char *p) { - struct stat st; - - assert(p); - - if (lstat(p, &st) < 0) - return -errno; - - return - (st.st_uid == 0 || st.st_uid == getuid()) && - (st.st_mode & S_ISVTX); -} - static const char *const ioprio_class_table[] = { [IOPRIO_CLASS_NONE] = "none", [IOPRIO_CLASS_RT] = "realtime", @@ -6134,27 +6199,28 @@ int split_pair(const char *s, const char *sep, char **l, char **r) { int shall_restore_state(void) { _cleanup_free_ char *line = NULL; - const char *word, *state; - size_t l; + const char *p; int r; r = proc_cmdline(&line); if (r < 0) return r; - if (r == 0) /* Container ... */ - return 1; r = 1; + p = line; - FOREACH_WORD_QUOTED(word, l, line, state) { + for (;;) { + _cleanup_free_ char *word = NULL; const char *e; - char n[l+1]; int k; - memcpy(n, word, l); - n[l] = 0; + k = unquote_first_word(&p, &word, true); + if (k < 0) + return k; + if (k == 0) + break; - e = startswith(n, "systemd.restore_state="); + e = startswith(word, "systemd.restore_state="); if (!e) continue; @@ -6167,51 +6233,35 @@ int shall_restore_state(void) { } int proc_cmdline(char **ret) { - int r; - - if (detect_container(NULL) > 0) { - char *buf = NULL, *p; - size_t sz = 0; - - r = read_full_file("/proc/1/cmdline", &buf, &sz); - if (r < 0) - return r; - - for (p = buf; p + 1 < buf + sz; p++) - if (*p == 0) - *p = ' '; - - *p = 0; - *ret = buf; - return 1; - } - - r = read_one_line_file("/proc/cmdline", ret); - if (r < 0) - return r; + assert(ret); - return 1; + if (detect_container(NULL) > 0) + return get_process_cmdline(1, 0, false, ret); + else + return read_one_line_file("/proc/cmdline", ret); } int parse_proc_cmdline(int (*parse_item)(const char *key, const char *value)) { _cleanup_free_ char *line = NULL; - const char *w, *state; - size_t l; + const char *p; int r; assert(parse_item); r = proc_cmdline(&line); if (r < 0) - log_warning("Failed to read /proc/cmdline, ignoring: %s", strerror(-r)); - if (r <= 0) - return 0; + return r; - FOREACH_WORD_QUOTED(w, l, line, state) { - char word[l+1], *value; + p = line; + for (;;) { + _cleanup_free_ char *word = NULL; + char *value = NULL; - memcpy(word, w, l); - word[l] = 0; + r = unquote_first_word(&p, &word, true); + if (r < 0) + return r; + if (r == 0) + break; /* Filter out arguments that are intended only for the * initrd */ @@ -6981,19 +7031,19 @@ int is_symlink(const char *path) { int is_dir(const char* path, bool follow) { struct stat st; + int r; - if (follow) { - if (stat(path, &st) < 0) - return -errno; - } else { - if (lstat(path, &st) < 0) - return -errno; - } + if (follow) + r = stat(path, &st); + else + r = lstat(path, &st); + if (r < 0) + return -errno; return !!S_ISDIR(st.st_mode); } -int unquote_first_word(const char **p, char **ret) { +int unquote_first_word(const char **p, char **ret, bool relax) { _cleanup_free_ char *s = NULL; size_t allocated = 0, sz = 0; @@ -7052,8 +7102,11 @@ int unquote_first_word(const char **p, char **ret) { break; case VALUE_ESCAPE: - if (c == 0) + if (c == 0) { + if (relax) + goto finish; return -EINVAL; + } if (!GREEDY_REALLOC(s, allocated, sz+2)) return -ENOMEM; @@ -7064,9 +7117,11 @@ int unquote_first_word(const char **p, char **ret) { break; case SINGLE_QUOTE: - if (c == 0) + if (c == 0) { + if (relax) + goto finish; return -EINVAL; - else if (c == '\'') + } else if (c == '\'') state = VALUE; else if (c == '\\') state = SINGLE_QUOTE_ESCAPE; @@ -7080,8 +7135,11 @@ int unquote_first_word(const char **p, char **ret) { break; case SINGLE_QUOTE_ESCAPE: - if (c == 0) + if (c == 0) { + if (relax) + goto finish; return -EINVAL; + } if (!GREEDY_REALLOC(s, allocated, sz+2)) return -ENOMEM; @@ -7107,8 +7165,11 @@ int unquote_first_word(const char **p, char **ret) { break; case DOUBLE_QUOTE_ESCAPE: - if (c == 0) + if (c == 0) { + if (relax) + goto finish; return -EINVAL; + } if (!GREEDY_REALLOC(s, allocated, sz+2)) return -ENOMEM; @@ -7168,7 +7229,7 @@ int unquote_many_words(const char **p, ...) { l = newa0(char*, n); for (c = 0; c < n; c++) { - r = unquote_first_word(p, &l[c]); + r = unquote_first_word(p, &l[c], false); if (r < 0) { int j; diff --git a/src/dhcp-manager/systemd-dhcp/src/shared/util.h b/src/dhcp-manager/systemd-dhcp/src/shared/util.h index f6ff8ea40f..e8913277fe 100644 --- a/src/dhcp-manager/systemd-dhcp/src/shared/util.h +++ b/src/dhcp-manager/systemd-dhcp/src/shared/util.h @@ -276,6 +276,7 @@ char **replace_env_argv(char **argv, char **env); 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); @@ -327,6 +328,7 @@ int make_console_stdio(void); int dev_urandom(void *p, size_t n); void random_bytes(void *p, size_t n); +void initialize_srand(void); static inline uint64_t random_u64(void) { uint64_t u; @@ -587,8 +589,6 @@ static inline bool _pure_ in_charset(const char *s, const char* charset) { int block_get_whole_disk(dev_t d, dev_t *ret); -int file_is_priv_sticky(const char *p); - #define NULSTR_FOREACH(i, l) \ for ((i) = (l); (i) && *(i); (i) = strchr((i), 0)+1) @@ -799,6 +799,15 @@ static inline void _reset_errno_(int *saved_errno) { #define PROTECT_ERRNO _cleanup_(_reset_errno_) __attribute__((unused)) int _saved_errno_ = errno +static inline int negative_errno(void) { + /* This helper should be used to shut up gcc if you know 'errno' is + * negative. Instead of "return -errno;", use "return negative_errno();" + * It will suppress bogus gcc warnings in case it assumes 'errno' might + * be 0 and thus the caller's error-handling might not be triggered. */ + assert_return(errno > 0, -EINVAL); + return -errno; +} + struct _umask_struct_ { mode_t mask; bool quit; @@ -835,6 +844,21 @@ static inline int log2i(int x) { return __SIZEOF_INT__ * 8 - __builtin_clz(x) - 1; } +static inline unsigned log2u(unsigned x) { + assert(x > 0); + + return sizeof(unsigned) * 8 - __builtin_clz(x) - 1; +} + +static inline unsigned log2u_round_up(unsigned x) { + assert(x > 0); + + if (x == 1) + return 0; + + return log2u(x - 1) + 1; +} + static inline bool logind_running(void) { return access("/run/systemd/seats/", F_OK) >= 0; } @@ -1003,7 +1027,7 @@ int take_password_lock(const char *root); int is_symlink(const char *path); int is_dir(const char *path, bool follow); -int unquote_first_word(const char **p, char **ret); +int unquote_first_word(const char **p, char **ret, bool relax); int unquote_many_words(const char **p, ...) _sentinel_; int free_and_strdup(char **p, const char *s); diff --git a/src/dhcp-manager/systemd-dhcp/src/systemd/sd-event.h b/src/dhcp-manager/systemd-dhcp/src/systemd/sd-event.h index 0dbdcdf2a5..25a10f99ab 100644 --- a/src/dhcp-manager/systemd-dhcp/src/systemd/sd-event.h +++ b/src/dhcp-manager/systemd-dhcp/src/systemd/sd-event.h @@ -109,8 +109,8 @@ sd_event *sd_event_source_get_event(sd_event_source *s); void* sd_event_source_get_userdata(sd_event_source *s); void* sd_event_source_set_userdata(sd_event_source *s, void *userdata); -int sd_event_source_set_name(sd_event_source *s, const char *name); -int sd_event_source_get_name(sd_event_source *s, const char **name); +int sd_event_source_set_description(sd_event_source *s, const char *description); +int sd_event_source_get_description(sd_event_source *s, const char **description); int sd_event_source_set_prepare(sd_event_source *s, sd_event_handler_t callback); int sd_event_source_get_pending(sd_event_source *s); int sd_event_source_get_priority(sd_event_source *s, int64_t *priority); |