systemd: merge branch 'systemd' into master

This commit is contained in:
Thomas Haller
2015-08-12 12:53:13 +02:00
20 changed files with 1125 additions and 187 deletions

View File

@@ -222,7 +222,8 @@ lease_to_ip4_config (const char *iface,
guint16 mtu;
int r, num;
guint64 end_time;
uint8_t *data;
const uint8_t *data;
gsize data_len;
gboolean metered = FALSE;
g_return_val_if_fail (lease != NULL, NULL);
@@ -355,9 +356,9 @@ lease_to_ip4_config (const char *iface,
g_string_free (l, TRUE);
}
num = sd_dhcp_lease_get_vendor_specific (lease, &data);
if (num > 0)
metered = !!memmem (data, num, "ANDROID_METERED", STRLEN ("ANDROID_METERED"));
r = sd_dhcp_lease_get_vendor_specific (lease, &data, &data_len);
if (r >= 0)
metered = !!memmem (data, data_len, "ANDROID_METERED", STRLEN ("ANDROID_METERED"));
nm_ip4_config_set_metered (ip4_config, metered);
return ip4_config;

View File

@@ -29,60 +29,19 @@
#include "ctype.h"
#include "fileio.h"
int write_string_stream(FILE *f, const char *line) {
int write_string_stream(FILE *f, const char *line, bool enforce_newline) {
assert(f);
assert(line);
errno = 0;
fputs(line, f);
if (!endswith(line, "\n"))
if (enforce_newline && !endswith(line, "\n"))
fputc('\n', f);
fflush(f);
if (ferror(f))
return errno ? -errno : -EIO;
return 0;
return fflush_and_check(f);
}
int write_string_file(const char *fn, const char *line) {
_cleanup_fclose_ FILE *f = NULL;
assert(fn);
assert(line);
f = fopen(fn, "we");
if (!f)
return -errno;
return write_string_stream(f, line);
}
int write_string_file_no_create(const char *fn, const char *line) {
_cleanup_fclose_ FILE *f = NULL;
int fd;
assert(fn);
assert(line);
/* We manually build our own version of fopen(..., "we") that
* works without O_CREAT */
fd = open(fn, O_WRONLY|O_CLOEXEC|O_NOCTTY);
if (fd < 0)
return -errno;
f = fdopen(fd, "we");
if (!f) {
safe_close(fd);
return -errno;
}
return write_string_stream(f, line);
}
int write_string_file_atomic(const char *fn, const char *line) {
static int write_string_file_atomic(const char *fn, const char *line, bool enforce_newline) {
_cleanup_fclose_ FILE *f = NULL;
_cleanup_free_ char *p = NULL;
int r;
@@ -96,7 +55,7 @@ int write_string_file_atomic(const char *fn, const char *line) {
fchmod_umask(fileno(f), 0644);
r = write_string_stream(f, line);
r = write_string_stream(f, line, enforce_newline);
if (r >= 0) {
if (rename(p, fn) < 0)
r = -errno;
@@ -108,6 +67,41 @@ int write_string_file_atomic(const char *fn, const char *line) {
return r;
}
int write_string_file(const char *fn, const char *line, WriteStringFileFlags flags) {
_cleanup_fclose_ FILE *f = NULL;
assert(fn);
assert(line);
if (flags & WRITE_STRING_FILE_ATOMIC) {
assert(flags & WRITE_STRING_FILE_CREATE);
return write_string_file_atomic(fn, line, !(flags & WRITE_STRING_FILE_AVOID_NEWLINE));
}
if (flags & WRITE_STRING_FILE_CREATE) {
f = fopen(fn, "we");
if (!f)
return -errno;
} else {
int fd;
/* We manually build our own version of fopen(..., "we") that
* works without O_CREAT */
fd = open(fn, O_WRONLY|O_CLOEXEC|O_NOCTTY);
if (fd < 0)
return -errno;
f = fdopen(fd, "we");
if (!f) {
safe_close(fd);
return -errno;
}
}
return write_string_stream(f, line, !(flags & WRITE_STRING_FILE_AVOID_NEWLINE));
}
int read_one_line_file(const char *fn, char **line) {
_cleanup_fclose_ FILE *f = NULL;
char t[LINE_MAX], *c;
@@ -136,6 +130,17 @@ int read_one_line_file(const char *fn, char **line) {
return 0;
}
int verify_one_line_file(const char *fn, const char *line) {
_cleanup_free_ char *value = NULL;
int r;
r = read_one_line_file(fn, &value);
if (r < 0)
return r;
return streq(value, line);
}
int read_full_stream(FILE *f, char **contents, size_t *size) {
size_t n, l;
_cleanup_free_ char *buf = NULL;
@@ -777,7 +782,7 @@ int executable_is_script(const char *path, char **interpreter) {
*/
int get_status_field(const char *filename, const char *pattern, char **field) {
_cleanup_free_ char *status = NULL;
char *t;
char *t, *f;
size_t len;
int r;
@@ -811,9 +816,10 @@ int get_status_field(const char *filename, const char *pattern, char **field) {
len = strcspn(t, WHITESPACE);
*field = strndup(t, len);
if (!*field)
f = strndup(t, len);
if (!f)
return -ENOMEM;
*field = f;
return 0;
}

View File

@@ -28,15 +28,21 @@
#include "macro.h"
int write_string_stream(FILE *f, const char *line);
int write_string_file(const char *fn, const char *line);
int write_string_file_no_create(const char *fn, const char *line);
int write_string_file_atomic(const char *fn, const char *line);
typedef enum {
WRITE_STRING_FILE_CREATE = 1,
WRITE_STRING_FILE_ATOMIC = 2,
WRITE_STRING_FILE_AVOID_NEWLINE = 4,
} WriteStringFileFlags;
int write_string_stream(FILE *f, const char *line, bool enforce_newline);
int write_string_file(const char *fn, const char *line, WriteStringFileFlags flags);
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);
int verify_one_line_file(const char *fn, const char *line);
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);
int load_env_file_pairs(FILE *f, const char *fname, const char *separator, char ***l);

View File

@@ -63,14 +63,22 @@ static bool hostname_valid_char(char c) {
c == '.';
}
bool hostname_is_valid(const char *s) {
/**
* Check if s looks like a valid host name or fqdn. This does not do
* full DNS validation, but only checks if the name is composed of
* allowed characters and the length is not above the maximum allowed
* by Linux (c.f. dns_name_is_valid()). Trailing dot is allowed if
* relax is true and at least two components are present in the name.
*/
bool hostname_is_valid(const char *s, bool relax) {
const char *p;
bool dot;
unsigned dots = 0;
if (isempty(s))
return false;
/* Doesn't accept empty hostnames, hostnames with trailing or
/* Doesn't accept empty hostnames, hostnames with
* leading dots, and hostnames with multiple dots in a
* sequence. Also ensures that the length stays below
* HOST_NAME_MAX. */
@@ -81,6 +89,7 @@ bool hostname_is_valid(const char *s) {
return false;
dot = true;
dots ++;
} else {
if (!hostname_valid_char(*p))
return false;
@@ -89,7 +98,7 @@ bool hostname_is_valid(const char *s) {
}
}
if (dot)
if (dot && (dots < 2 || !relax))
return false;
if (p-s > HOST_NAME_MAX)
@@ -98,7 +107,7 @@ bool hostname_is_valid(const char *s) {
return true;
}
char* hostname_cleanup(char *s, bool lowercase) {
char* hostname_cleanup(char *s) {
char *p, *d;
bool dot;
@@ -112,7 +121,7 @@ char* hostname_cleanup(char *s, bool lowercase) {
*(d++) = '.';
dot = true;
} else if (hostname_valid_char(*p)) {
*(d++) = lowercase ? tolower(*p) : *p;
*(d++) = *p;
dot = false;
}
@@ -134,14 +143,14 @@ bool is_localhost(const char *hostname) {
/* This tries to identify local host and domain names
* described in RFC6761 plus the redhatism of .localdomain */
return streq(hostname, "localhost") ||
streq(hostname, "localhost.") ||
streq(hostname, "localdomain.") ||
streq(hostname, "localdomain") ||
endswith(hostname, ".localhost") ||
endswith(hostname, ".localhost.") ||
endswith(hostname, ".localdomain") ||
endswith(hostname, ".localdomain.");
return strcaseeq(hostname, "localhost") ||
strcaseeq(hostname, "localhost.") ||
strcaseeq(hostname, "localdomain.") ||
strcaseeq(hostname, "localdomain") ||
endswith_no_case(hostname, ".localhost") ||
endswith_no_case(hostname, ".localhost.") ||
endswith_no_case(hostname, ".localdomain") ||
endswith_no_case(hostname, ".localdomain.");
}
#if 0 /* NM_IGNORED */
@@ -179,7 +188,7 @@ int read_hostname_config(const char *path, char **hostname) {
truncate_nl(l);
if (l[0] != '\0' && l[0] != '#') {
/* found line with value */
name = hostname_cleanup(l, false);
name = hostname_cleanup(l);
name = strdup(name);
if (!name)
return -ENOMEM;

View File

@@ -31,8 +31,8 @@ bool hostname_is_set(void);
char* gethostname_malloc(void);
bool hostname_is_valid(const char *s) _pure_;
char* hostname_cleanup(char *s, bool lowercase);
bool hostname_is_valid(const char *s, bool relax) _pure_;
char* hostname_cleanup(char *s);
bool is_localhost(const char *hostname);

View File

@@ -125,6 +125,32 @@
} \
} while(false)
/* Insert an item before another one (a = where, b = what) */
#define LIST_INSERT_BEFORE(name,head,a,b) \
do { \
typeof(*(head)) **_head = &(head), *_a = (a), *_b = (b); \
assert(_b); \
if (!_a) { \
if (!*_head) { \
_b->name##_next = NULL; \
_b->name##_prev = NULL; \
*_head = _b; \
} else { \
typeof(*(head)) *_tail = (head); \
while (_tail->name##_next) \
_tail = _tail->name##_next; \
_b->name##_next = NULL; \
_b->name##_prev = _tail; \
_tail->name##_next = _b; \
} \
} else { \
if ((_b->name##_prev = _a->name##_prev)) \
_b->name##_prev->name##_next = _b; \
_b->name##_next = _a; \
_a->name##_prev = _b; \
} \
} while(false)
#define LIST_JUST_US(name,item) \
(!(item)->name##_prev && !(item)->name##_next) \

View File

@@ -28,6 +28,7 @@
#include <sys/types.h>
#include <sys/uio.h>
#include <inttypes.h>
#include <stdbool.h>
#define _printf_(a,b) __attribute__ ((format (printf, a, b)))
#define _alloc_(...) __attribute__ ((alloc_size(__VA_ARGS__)))
@@ -408,12 +409,12 @@ do { \
#define IN_SET(x, y, ...) \
({ \
const typeof(y) _y = (y); \
typeof(_y) _x = (x); \
static const typeof(y) _array[] = { (y), __VA_ARGS__ }; \
const typeof(y) _x = (x); \
unsigned _i; \
bool _found = false; \
for (_i = 0; _i < 1 + sizeof((typeof(_x)[]) { __VA_ARGS__ })/sizeof(typeof(_x)); _i++) \
if (((typeof(_x)[]) { _y, __VA_ARGS__ })[_i] == _x) { \
for (_i = 0; _i < ELEMENTSOF(_array); _i++) \
if (_array[_i] == _x) { \
_found = true; \
break; \
} \
@@ -465,6 +466,18 @@ do { \
#define MODE_INVALID ((mode_t) -1)
#endif /* NM_IGNORED */
static inline bool UID_IS_INVALID(uid_t uid) {
/* We consider both the old 16bit -1 user and the newer 32bit
* -1 user invalid, since they are or used to be incompatible
* with syscalls such as setresuid() or chown(). */
return uid == (uid_t) ((uint32_t) -1) || uid == (uid_t) ((uint16_t) -1);
}
static inline bool GID_IS_INVALID(gid_t gid) {
return gid == (gid_t) ((uint32_t) -1) || gid == (gid_t) ((uint16_t) -1);
}
#define DEFINE_TRIVIAL_CLEANUP_FUNC(type, func) \
static inline void func##p(type *p) { \
if (*p) \

View File

@@ -535,7 +535,7 @@ int fd_is_mount_point(int fd, const char *filename, int flags) {
*
* If that didn't work we will try to read the mount id from
* /proc/self/fdinfo/<fd>. This is almost as good as
* name_to_handle_at(), however, does not return the the
* name_to_handle_at(), however, does not return the
* opaque file handle. The opaque file handle is pretty useful
* to detect the root directory, which we should always
* consider a mount point. Hence we use this only as
@@ -663,9 +663,11 @@ int path_is_mount_point(const char *t, int flags) {
canonical = canonicalize_file_name(t);
if (!canonical)
return -errno;
t = canonical;
}
r = path_get_parent(canonical ?: t, &parent);
r = path_get_parent(t, &parent);
if (r < 0)
return r;
@@ -673,7 +675,7 @@ int path_is_mount_point(const char *t, int flags) {
if (fd < 0)
return -errno;
return fd_is_mount_point(fd, basename(canonical ?: t), flags);
return fd_is_mount_point(fd, basename(t), flags);
}
int path_is_read_only_fs(const char *path) {

View File

@@ -125,17 +125,23 @@ size_t page_size(void) {
}
#endif /* NM_IGNORED */
bool streq_ptr(const char *a, const char *b) {
/* Like streq(), but tries to make sense of NULL pointers */
int strcmp_ptr(const char *a, const char *b) {
/* Like strcmp(), but tries to make sense of NULL pointers */
if (a && b)
return streq(a, b);
return strcmp(a, b);
if (!a && !b)
return true;
if (!a && b)
return -1;
return false;
if (a && !b)
return 1;
return 0;
}
bool streq_ptr(const char *a, const char *b) {
return strcmp_ptr(a, b) == 0;
}
char* endswith(const char *s, const char *postfix) {
@@ -331,6 +337,7 @@ void close_many(const int fds[], unsigned n_fd) {
for (i = 0; i < n_fd; i++)
safe_close(fds[i]);
}
#endif /* NM_IGNORED */
int unlink_noerrno(const char *path) {
PROTECT_ERRNO;
@@ -343,6 +350,7 @@ int unlink_noerrno(const char *path) {
return 0;
}
#if 0 /* NM_IGNORED */
int parse_boolean(const char *v) {
assert(v);
@@ -934,32 +942,573 @@ char *hexmem(const void *p, size_t l) {
return r;
}
void *unhexmem(const char *p, size_t l) {
uint8_t *r, *z;
int unhexmem(const char *p, size_t l, void **mem, size_t *len) {
_cleanup_free_ uint8_t *r = NULL;
uint8_t *z;
const char *x;
assert(mem);
assert(len);
assert(p);
z = r = malloc((l + 1) / 2 + 1);
if (!r)
return NULL;
return -ENOMEM;
for (x = p; x < p + l; x += 2) {
int a, b;
a = unhexchar(x[0]);
if (x+1 < p + l)
if (a < 0)
return a;
else if (x+1 < p + l) {
b = unhexchar(x[1]);
else
if (b < 0)
return b;
} else
b = 0;
*(z++) = (uint8_t) a << 4 | (uint8_t) b;
}
*z = 0;
*mem = r;
r = NULL;
*len = (l + 1) / 2;
return 0;
}
/* https://tools.ietf.org/html/rfc4648#section-6
* Notice that base32hex differs from base32 in the alphabet it uses.
* The distinction is that the base32hex representation preserves the
* order of the underlying data when compared as bytestrings, this is
* useful when representing NSEC3 hashes, as one can then verify the
* order of hashes directly from their representation. */
char base32hexchar(int x) {
static const char table[32] = "0123456789"
"ABCDEFGHIJKLMNOPQRSTUV";
return table[x & 31];
}
int unbase32hexchar(char c) {
unsigned offset;
if (c >= '0' && c <= '9')
return c - '0';
offset = '9' - '0' + 1;
if (c >= 'A' && c <= 'V')
return c - 'A' + offset;
return -EINVAL;
}
char *base32hexmem(const void *p, size_t l, bool padding) {
char *r, *z;
const uint8_t *x;
size_t len;
if (padding)
/* five input bytes makes eight output bytes, padding is added so we must round up */
len = 8 * (l + 4) / 5;
else {
/* same, but round down as there is no padding */
len = 8 * l / 5;
switch (l % 5) {
case 4:
len += 7;
break;
case 3:
len += 5;
break;
case 2:
len += 4;
break;
case 1:
len += 2;
break;
}
}
z = r = malloc(len + 1);
if (!r)
return NULL;
for (x = p; x < (const uint8_t*) p + (l / 5) * 5; x += 5) {
/* x[0] == XXXXXXXX; x[1] == YYYYYYYY; x[2] == ZZZZZZZZ
x[3] == QQQQQQQQ; x[4] == WWWWWWWW */
*(z++) = base32hexchar(x[0] >> 3); /* 000XXXXX */
*(z++) = base32hexchar((x[0] & 7) << 2 | x[1] >> 6); /* 000XXXYY */
*(z++) = base32hexchar((x[1] & 63) >> 1); /* 000YYYYY */
*(z++) = base32hexchar((x[1] & 1) << 4 | x[2] >> 4); /* 000YZZZZ */
*(z++) = base32hexchar((x[2] & 15) << 1 | x[3] >> 7); /* 000ZZZZQ */
*(z++) = base32hexchar((x[3] & 127) >> 2); /* 000QQQQQ */
*(z++) = base32hexchar((x[3] & 3) << 3 | x[4] >> 5); /* 000QQWWW */
*(z++) = base32hexchar((x[4] & 31)); /* 000WWWWW */
}
switch (l % 5) {
case 4:
*(z++) = base32hexchar(x[0] >> 3); /* 000XXXXX */
*(z++) = base32hexchar((x[0] & 7) << 2 | x[1] >> 6); /* 000XXXYY */
*(z++) = base32hexchar((x[1] & 63) >> 1); /* 000YYYYY */
*(z++) = base32hexchar((x[1] & 1) << 4 | x[2] >> 4); /* 000YZZZZ */
*(z++) = base32hexchar((x[2] & 15) << 1 | x[3] >> 7); /* 000ZZZZQ */
*(z++) = base32hexchar((x[3] & 127) >> 2); /* 000QQQQQ */
*(z++) = base32hexchar((x[3] & 3) << 3); /* 000QQ000 */
if (padding)
*(z++) = '=';
break;
case 3:
*(z++) = base32hexchar(x[0] >> 3); /* 000XXXXX */
*(z++) = base32hexchar((x[0] & 7) << 2 | x[1] >> 6); /* 000XXXYY */
*(z++) = base32hexchar((x[1] & 63) >> 1); /* 000YYYYY */
*(z++) = base32hexchar((x[1] & 1) << 4 | x[2] >> 4); /* 000YZZZZ */
*(z++) = base32hexchar((x[2] & 15) << 1); /* 000ZZZZ0 */
if (padding) {
*(z++) = '=';
*(z++) = '=';
*(z++) = '=';
}
break;
case 2:
*(z++) = base32hexchar(x[0] >> 3); /* 000XXXXX */
*(z++) = base32hexchar((x[0] & 7) << 2 | x[1] >> 6); /* 000XXXYY */
*(z++) = base32hexchar((x[1] & 63) >> 1); /* 000YYYYY */
*(z++) = base32hexchar((x[1] & 1) << 4); /* 000Y0000 */
if (padding) {
*(z++) = '=';
*(z++) = '=';
*(z++) = '=';
*(z++) = '=';
}
break;
case 1:
*(z++) = base32hexchar(x[0] >> 3); /* 000XXXXX */
*(z++) = base32hexchar((x[0] & 7) << 2); /* 000XXX00 */
if (padding) {
*(z++) = '=';
*(z++) = '=';
*(z++) = '=';
*(z++) = '=';
*(z++) = '=';
*(z++) = '=';
}
break;
}
*z = 0;
return r;
}
int unbase32hexmem(const char *p, size_t l, bool padding, void **mem, size_t *_len) {
_cleanup_free_ uint8_t *r = NULL;
int a, b, c, d, e, f, g, h;
uint8_t *z;
const char *x;
size_t len;
unsigned pad = 0;
assert(p);
/* padding ensures any base32hex input has input divisible by 8 */
if (padding && l % 8 != 0)
return -EINVAL;
if (padding) {
/* strip the padding */
while (l > 0 && p[l - 1] == '=' && pad < 7) {
pad ++;
l --;
}
}
/* a group of eight input bytes needs five output bytes, in case of
padding we need to add some extra bytes */
len = (l / 8) * 5;
switch (l % 8) {
case 7:
len += 4;
break;
case 5:
len += 3;
break;
case 4:
len += 2;
break;
case 2:
len += 1;
break;
case 0:
break;
default:
return -EINVAL;
}
z = r = malloc(len + 1);
if (!r)
return -ENOMEM;
for (x = p; x < p + (l / 8) * 8; x += 8) {
/* a == 000XXXXX; b == 000YYYYY; c == 000ZZZZZ; d == 000WWWWW
e == 000SSSSS; f == 000QQQQQ; g == 000VVVVV; h == 000RRRRR */
a = unbase32hexchar(x[0]);
if (a < 0)
return -EINVAL;
b = unbase32hexchar(x[1]);
if (b < 0)
return -EINVAL;
c = unbase32hexchar(x[2]);
if (c < 0)
return -EINVAL;
d = unbase32hexchar(x[3]);
if (d < 0)
return -EINVAL;
e = unbase32hexchar(x[4]);
if (e < 0)
return -EINVAL;
f = unbase32hexchar(x[5]);
if (f < 0)
return -EINVAL;
g = unbase32hexchar(x[6]);
if (g < 0)
return -EINVAL;
h = unbase32hexchar(x[7]);
if (h < 0)
return -EINVAL;
*(z++) = (uint8_t) a << 3 | (uint8_t) b >> 2; /* XXXXXYYY */
*(z++) = (uint8_t) b << 6 | (uint8_t) c << 1 | (uint8_t) d >> 4; /* YYZZZZZW */
*(z++) = (uint8_t) d << 4 | (uint8_t) e >> 1; /* WWWWSSSS */
*(z++) = (uint8_t) e << 7 | (uint8_t) f << 2 | (uint8_t) g >> 3; /* SQQQQQVV */
*(z++) = (uint8_t) g << 5 | (uint8_t) h; /* VVVRRRRR */
}
switch (l % 8) {
case 7:
a = unbase32hexchar(x[0]);
if (a < 0)
return -EINVAL;
b = unbase32hexchar(x[1]);
if (b < 0)
return -EINVAL;
c = unbase32hexchar(x[2]);
if (c < 0)
return -EINVAL;
d = unbase32hexchar(x[3]);
if (d < 0)
return -EINVAL;
e = unbase32hexchar(x[4]);
if (e < 0)
return -EINVAL;
f = unbase32hexchar(x[5]);
if (f < 0)
return -EINVAL;
g = unbase32hexchar(x[6]);
if (g < 0)
return -EINVAL;
/* g == 000VV000 */
if (g & 7)
return -EINVAL;
*(z++) = (uint8_t) a << 3 | (uint8_t) b >> 2; /* XXXXXYYY */
*(z++) = (uint8_t) b << 6 | (uint8_t) c << 1 | (uint8_t) d >> 4; /* YYZZZZZW */
*(z++) = (uint8_t) d << 4 | (uint8_t) e >> 1; /* WWWWSSSS */
*(z++) = (uint8_t) e << 7 | (uint8_t) f << 2 | (uint8_t) g >> 3; /* SQQQQQVV */
break;
case 5:
a = unbase32hexchar(x[0]);
if (a < 0)
return -EINVAL;
b = unbase32hexchar(x[1]);
if (b < 0)
return -EINVAL;
c = unbase32hexchar(x[2]);
if (c < 0)
return -EINVAL;
d = unbase32hexchar(x[3]);
if (d < 0)
return -EINVAL;
e = unbase32hexchar(x[4]);
if (e < 0)
return -EINVAL;
/* e == 000SSSS0 */
if (e & 1)
return -EINVAL;
*(z++) = (uint8_t) a << 3 | (uint8_t) b >> 2; /* XXXXXYYY */
*(z++) = (uint8_t) b << 6 | (uint8_t) c << 1 | (uint8_t) d >> 4; /* YYZZZZZW */
*(z++) = (uint8_t) d << 4 | (uint8_t) e >> 1; /* WWWWSSSS */
break;
case 4:
a = unbase32hexchar(x[0]);
if (a < 0)
return -EINVAL;
b = unbase32hexchar(x[1]);
if (b < 0)
return -EINVAL;
c = unbase32hexchar(x[2]);
if (c < 0)
return -EINVAL;
d = unbase32hexchar(x[3]);
if (d < 0)
return -EINVAL;
/* d == 000W0000 */
if (d & 15)
return -EINVAL;
*(z++) = (uint8_t) a << 3 | (uint8_t) b >> 2; /* XXXXXYYY */
*(z++) = (uint8_t) b << 6 | (uint8_t) c << 1 | (uint8_t) d >> 4; /* YYZZZZZW */
break;
case 2:
a = unbase32hexchar(x[0]);
if (a < 0)
return -EINVAL;
b = unbase32hexchar(x[1]);
if (b < 0)
return -EINVAL;
/* b == 000YYY00 */
if (b & 3)
return -EINVAL;
*(z++) = (uint8_t) a << 3 | (uint8_t) b >> 2; /* XXXXXYYY */
break;
case 0:
break;
default:
return -EINVAL;
}
*z = 0;
*mem = r;
r = NULL;
*_len = len;
return 0;
}
/* https://tools.ietf.org/html/rfc4648#section-4 */
char base64char(int x) {
static const char table[64] = "ABCDEFGHIJKLMNOPQRSTUVWXYZ"
"abcdefghijklmnopqrstuvwxyz"
"0123456789+/";
return table[x & 63];
}
int unbase64char(char c) {
unsigned offset;
if (c >= 'A' && c <= 'Z')
return c - 'A';
offset = 'Z' - 'A' + 1;
if (c >= 'a' && c <= 'z')
return c - 'a' + offset;
offset += 'z' - 'a' + 1;
if (c >= '0' && c <= '9')
return c - '0' + offset;
offset += '9' - '0' + 1;
if (c == '+')
return offset;
offset ++;
if (c == '/')
return offset;
return -EINVAL;
}
char *base64mem(const void *p, size_t l) {
char *r, *z;
const uint8_t *x;
/* three input bytes makes four output bytes, padding is added so we must round up */
z = r = malloc(4 * (l + 2) / 3 + 1);
if (!r)
return NULL;
for (x = p; x < (const uint8_t*) p + (l / 3) * 3; x += 3) {
/* x[0] == XXXXXXXX; x[1] == YYYYYYYY; x[2] == ZZZZZZZZ */
*(z++) = base64char(x[0] >> 2); /* 00XXXXXX */
*(z++) = base64char((x[0] & 3) << 4 | x[1] >> 4); /* 00XXYYYY */
*(z++) = base64char((x[1] & 15) << 2 | x[2] >> 6); /* 00YYYYZZ */
*(z++) = base64char(x[2] & 63); /* 00ZZZZZZ */
}
switch (l % 3) {
case 2:
*(z++) = base64char(x[0] >> 2); /* 00XXXXXX */
*(z++) = base64char((x[0] & 3) << 4 | x[1] >> 4); /* 00XXYYYY */
*(z++) = base64char((x[1] & 15) << 2); /* 00YYYY00 */
*(z++) = '=';
break;
case 1:
*(z++) = base64char(x[0] >> 2); /* 00XXXXXX */
*(z++) = base64char((x[0] & 3) << 4); /* 00XX0000 */
*(z++) = '=';
*(z++) = '=';
break;
}
*z = 0;
return r;
}
int unbase64mem(const char *p, size_t l, void **mem, size_t *_len) {
_cleanup_free_ uint8_t *r = NULL;
int a, b, c, d;
uint8_t *z;
const char *x;
size_t len;
assert(p);
/* padding ensures any base63 input has input divisible by 4 */
if (l % 4 != 0)
return -EINVAL;
/* strip the padding */
if (l > 0 && p[l - 1] == '=')
l --;
if (l > 0 && p[l - 1] == '=')
l --;
/* a group of four input bytes needs three output bytes, in case of
padding we need to add two or three extra bytes */
len = (l / 4) * 3 + (l % 4 ? (l % 4) - 1 : 0);
z = r = malloc(len + 1);
if (!r)
return -ENOMEM;
for (x = p; x < p + (l / 4) * 4; x += 4) {
/* a == 00XXXXXX; b == 00YYYYYY; c == 00ZZZZZZ; d == 00WWWWWW */
a = unbase64char(x[0]);
if (a < 0)
return -EINVAL;
b = unbase64char(x[1]);
if (b < 0)
return -EINVAL;
c = unbase64char(x[2]);
if (c < 0)
return -EINVAL;
d = unbase64char(x[3]);
if (d < 0)
return -EINVAL;
*(z++) = (uint8_t) a << 2 | (uint8_t) b >> 4; /* XXXXXXYY */
*(z++) = (uint8_t) b << 4 | (uint8_t) c >> 2; /* YYYYZZZZ */
*(z++) = (uint8_t) c << 6 | (uint8_t) d; /* ZZWWWWWW */
}
switch (l % 4) {
case 3:
a = unbase64char(x[0]);
if (a < 0)
return -EINVAL;
b = unbase64char(x[1]);
if (b < 0)
return -EINVAL;
c = unbase64char(x[2]);
if (c < 0)
return -EINVAL;
/* c == 00ZZZZ00 */
if (c & 3)
return -EINVAL;
*(z++) = (uint8_t) a << 2 | (uint8_t) b >> 4; /* XXXXXXYY */
*(z++) = (uint8_t) b << 4 | (uint8_t) c >> 2; /* YYYYZZZZ */
break;
case 2:
a = unbase64char(x[0]);
if (a < 0)
return -EINVAL;
b = unbase64char(x[1]);
if (b < 0)
return -EINVAL;
/* b == 00YY0000 */
if (b & 15)
return -EINVAL;
*(z++) = (uint8_t) a << 2 | (uint8_t) (b >> 4); /* XXXXXXYY */
break;
case 0:
break;
default:
return -EINVAL;
}
*z = 0;
*mem = r;
r = NULL;
*_len = len;
return 0;
}
char octchar(int x) {
return '0' + (x & 7);
}
@@ -2486,7 +3035,7 @@ char* strshorten(char *s, size_t l) {
#if 0 /* NM_IGNORED */
bool machine_name_is_valid(const char *s) {
if (!hostname_is_valid(s))
if (!hostname_is_valid(s, false))
return false;
/* Machine names should be useful hostnames, but also be
@@ -2559,8 +3108,9 @@ int fopen_temporary(const char *path, FILE **_f, char **_temp_path) {
f = fdopen(fd, "we");
if (!f) {
unlink(t);
unlink_noerrno(t);
free(t);
safe_close(fd);
return -errno;
}
@@ -4755,7 +5305,7 @@ int update_reboot_param_file(const char *param) {
if (param) {
r = write_string_file(REBOOT_PARAM_FILE, param);
r = write_string_file(REBOOT_PARAM_FILE, param, WRITE_STRING_FILE_CREATE);
if (r < 0)
log_error("Failed to write reboot param to "
REBOOT_PARAM_FILE": %s", strerror(-r));
@@ -5233,13 +5783,19 @@ int unquote_first_word(const char **p, char **ret, UnquoteFlags flags) {
case VALUE:
if (c == 0)
goto finish;
else if (c == '\'')
else if (c == '\'') {
if (!GREEDY_REALLOC(s, allocated, sz+1))
return -ENOMEM;
state = SINGLE_QUOTE;
else if (c == '\\')
} else if (c == '\\')
state = VALUE_ESCAPE;
else if (c == '\"')
else if (c == '\"') {
if (!GREEDY_REALLOC(s, allocated, sz+1))
return -ENOMEM;
state = DOUBLE_QUOTE;
else if (strchr(WHITESPACE, c))
} else if (strchr(WHITESPACE, c))
state = SPACE;
else {
if (!GREEDY_REALLOC(s, allocated, sz+2))
@@ -6092,4 +6648,74 @@ int reset_uid_gid(void) {
return 0;
}
int getxattr_malloc(const char *path, const char *name, char **value, bool allow_symlink) {
char *v;
size_t l;
ssize_t n;
assert(path);
assert(name);
assert(value);
for (l = 100; ; l = (size_t) n + 1) {
v = new0(char, l);
if (!v)
return -ENOMEM;
if (allow_symlink)
n = lgetxattr(path, name, v, l);
else
n = getxattr(path, name, v, l);
if (n >= 0 && (size_t) n < l) {
*value = v;
return n;
}
free(v);
if (n < 0 && errno != ERANGE)
return -errno;
if (allow_symlink)
n = lgetxattr(path, name, NULL, 0);
else
n = getxattr(path, name, NULL, 0);
if (n < 0)
return -errno;
}
}
int fgetxattr_malloc(int fd, const char *name, char **value) {
char *v;
size_t l;
ssize_t n;
assert(fd >= 0);
assert(name);
assert(value);
for (l = 100; ; l = (size_t) n + 1) {
v = new0(char, l);
if (!v)
return -ENOMEM;
n = fgetxattr(fd, name, v, l);
if (n >= 0 && (size_t) n < l) {
*value = v;
return n;
}
free(v);
if (n < 0 && errno != ERANGE)
return -errno;
n = fgetxattr(fd, name, NULL, 0);
if (n < 0)
return -errno;
}
}
#endif /* NM_IGNORED */

View File

@@ -77,6 +77,7 @@ size_t page_size(void) _pure_;
#define strncaseeq(a, b, n) (strncasecmp((a), (b), (n)) == 0)
bool streq_ptr(const char *a, const char *b) _pure_;
int strcmp_ptr(const char *a, const char *b) _pure_;
#define new(t, n) ((t*) malloc_multiply(sizeof(t), (n)))
@@ -90,6 +91,11 @@ bool streq_ptr(const char *a, const char *b) _pure_;
#define malloc0(n) (calloc((n), 1))
static inline void *mfree(void *memory) {
free(memory);
return NULL;
}
static inline const char* yes_no(bool b) {
return b ? "yes" : "no";
}
@@ -246,6 +252,10 @@ char octchar(int x) _const_;
int unoctchar(char c) _const_;
char decchar(int x) _const_;
int undecchar(char c) _const_;
char base32hexchar(int x) _const_;
int unbase32hexchar(char c) _const_;
char base64char(int x) _const_;
int unbase64char(char c) _const_;
char *cescape(const char *s);
size_t cescape_char(char c, char *buf);
@@ -620,7 +630,13 @@ static inline void *mempset(void *s, int c, size_t n) {
}
char *hexmem(const void *p, size_t l);
void *unhexmem(const char *p, size_t l);
int unhexmem(const char *p, size_t l, void **mem, size_t *len);
char *base32hexmem(const void *p, size_t l, bool padding);
int unbase32hexmem(const char *p, size_t l, bool padding, void **mem, size_t *len);
char *base64mem(const void *p, size_t l);
int unbase64mem(const char *p, size_t l, void **mem, size_t *len);
char *strextend(char **x, ...) _sentinel_;
char *strrep(const char *s, unsigned n);
@@ -858,6 +874,11 @@ int unquote_first_word(const char **p, char **ret, UnquoteFlags flags);
int unquote_first_word_and_warn(const char **p, char **ret, UnquoteFlags flags, const char *unit, const char *filename, unsigned line, const char *rvalue);
int unquote_many_words(const char **p, UnquoteFlags flags, ...) _sentinel_;
static inline void free_and_replace(char **s, char *v) {
free(*s);
*s = v;
}
int free_and_strdup(char **p, const char *s);
#define INOTIFY_EVENT_MAX (sizeof(struct inotify_event) + NAME_MAX + 1)
@@ -913,3 +934,6 @@ int parse_mode(const char *s, mode_t *ret);
int mount_move_root(const char *path);
int reset_uid_gid(void);
int getxattr_malloc(const char *path, const char *name, char **value, bool allow_symlink);
int fgetxattr_malloc(int fd, const char *name, char **value);

View File

@@ -29,6 +29,7 @@
#include "refcnt.h"
#include "util.h"
#include "list.h"
#include "dhcp-protocol.h"
@@ -40,6 +41,14 @@ struct sd_dhcp_route {
unsigned char dst_prefixlen;
};
struct sd_dhcp_raw_option {
LIST_FIELDS(struct sd_dhcp_raw_option, options);
uint8_t tag;
uint8_t length;
void *data;
};
struct sd_dhcp_lease {
RefCount n_ref;
@@ -75,12 +84,15 @@ struct sd_dhcp_lease {
uint8_t *client_id;
size_t client_id_len;
uint8_t *vendor_specific;
size_t vendor_specific_size;
size_t vendor_specific_len;
LIST_HEAD(struct sd_dhcp_raw_option, private_options);
};
int dhcp_lease_new(sd_dhcp_lease **ret);
int dhcp_lease_parse_options(uint8_t code, uint8_t len, const uint8_t *option,
void *user_data);
int dhcp_lease_insert_private_option(sd_dhcp_lease *lease, uint8_t tag,
const uint8_t *data, uint8_t len);
int dhcp_lease_set_default_subnet_mask(sd_dhcp_lease *lease);

View File

@@ -140,5 +140,7 @@ enum {
DHCP_OPTION_VENDOR_CLASS_IDENTIFIER = 60,
DHCP_OPTION_CLIENT_IDENTIFIER = 61,
DHCP_OPTION_CLASSLESS_STATIC_ROUTE = 121,
DHCP_OPTION_PRIVATE_BASE = 224,
DHCP_OPTION_PRIVATE_LAST = 254,
DHCP_OPTION_END = 255,
};

View File

@@ -519,3 +519,30 @@ int deserialize_dhcp_routes(struct sd_dhcp_route **ret, size_t *ret_size, size_t
return 0;
}
int serialize_dhcp_option(FILE *f, const char *key, const uint8_t *data, size_t size) {
_cleanup_free_ char *hex_buf = NULL;
assert(f);
assert(key);
assert(data);
hex_buf = hexmem(data, size);
if (hex_buf == NULL)
return -ENOMEM;
fprintf(f, "%s=%s\n", key, hex_buf);
return 0;
}
int deserialize_dhcp_option(uint8_t **data, size_t *data_len, const char *string) {
assert(data);
assert(data_len);
assert(string);
if (strlen(string) % 2)
return -EINVAL;
return unhexmem(string, strlen(string), (void **)data, data_len);
}

View File

@@ -78,3 +78,6 @@ struct sd_dhcp_route;
void serialize_dhcp_routes(FILE *f, const char *key, struct sd_dhcp_route *routes, size_t size);
int deserialize_dhcp_routes(struct sd_dhcp_route **ret, size_t *ret_size, size_t *ret_allocated, const char *string);
int serialize_dhcp_option(FILE *f, const char *key, const uint8_t *data, size_t size);
int deserialize_dhcp_option(uint8_t **data, size_t *data_len, const char *string);

View File

@@ -181,16 +181,18 @@ int sd_dhcp_lease_get_routes(sd_dhcp_lease *lease, struct sd_dhcp_route **routes
return 0;
}
int sd_dhcp_lease_get_vendor_specific(sd_dhcp_lease *lease, uint8_t **data) {
int sd_dhcp_lease_get_vendor_specific(sd_dhcp_lease *lease, const uint8_t **data,
size_t *data_len) {
assert_return(lease, -EINVAL);
assert_return(data, -EINVAL);
assert_return(data_len, -EINVAL);
if (lease->vendor_specific) {
*data = lease->vendor_specific;
return lease->vendor_specific_size;
} else
if (!lease->vendor_specific)
return -ENOENT;
*data = lease->vendor_specific;
*data_len = lease->vendor_specific_len;
return 0;
}
@@ -203,12 +205,21 @@ sd_dhcp_lease *sd_dhcp_lease_ref(sd_dhcp_lease *lease) {
sd_dhcp_lease *sd_dhcp_lease_unref(sd_dhcp_lease *lease) {
if (lease && REFCNT_DEC(lease->n_ref) == 0) {
while (lease->private_options) {
struct sd_dhcp_raw_option *option = lease->private_options;
LIST_REMOVE(options, lease->private_options, option);
free(option->data);
free(option);
}
free(lease->hostname);
free(lease->domainname);
free(lease->dns);
free(lease->ntp);
free(lease->static_route);
free(lease->client_id);
free(lease->vendor_specific);
free(lease);
}
@@ -289,24 +300,6 @@ static int lease_parse_string(const uint8_t *option, size_t len, char **ret) {
return 0;
}
static int lease_parse_binary(const uint8_t *option, size_t len, uint8_t **ret) {
assert (option);
assert (ret);
if (len >= 1) {
uint8_t *data;
data = memdup(option, len);
if (!data)
return -errno;
free(*ret);
*ret = data;
}
return 0;
}
static int lease_parse_in_addrs_aux(const uint8_t *option, size_t len, struct in_addr **ret, size_t *ret_size, size_t mult) {
assert(option);
assert(ret);
@@ -468,7 +461,8 @@ int dhcp_lease_parse_options(uint8_t code, uint8_t len, const uint8_t *option,
break;
case DHCP_OPTION_ROUTER:
lease_parse_be32(option, len, &lease->router);
if(len >= 4)
lease_parse_be32(option, 4, &lease->router);
break;
@@ -569,11 +563,10 @@ int dhcp_lease_parse_options(uint8_t code, uint8_t len, const uint8_t *option,
if (e)
*e = 0;
if (!hostname_is_valid(hostname) || is_localhost(hostname))
if (!hostname_is_valid(hostname, false) || is_localhost(hostname))
break;
free(lease->hostname);
lease->hostname = hostname;
free_and_replace(&lease->hostname, hostname);
hostname = NULL;
break;
@@ -614,17 +607,58 @@ int dhcp_lease_parse_options(uint8_t code, uint8_t len, const uint8_t *option,
break;
case DHCP_OPTION_VENDOR_SPECIFIC:
r = lease_parse_binary(option, len, &lease->vendor_specific);
if (r < 0)
return r;
lease->vendor_specific_size = len;
if (len >= 1) {
free(lease->vendor_specific);
lease->vendor_specific = memdup(option, len);
if (!lease->vendor_specific)
return -ENOMEM;
lease->vendor_specific_len = len;
}
break;
default:
if (code < DHCP_OPTION_PRIVATE_BASE || code > DHCP_OPTION_PRIVATE_LAST)
break;
r = dhcp_lease_insert_private_option(lease, code, option, len);
if (r < 0)
return r;
}
return 0;
}
int dhcp_lease_insert_private_option(sd_dhcp_lease *lease, uint8_t tag,
const uint8_t *data, uint8_t len) {
struct sd_dhcp_raw_option *cur, *option;
LIST_FOREACH(options, cur, lease->private_options) {
if (tag < cur->tag)
break;
else if (tag == cur->tag) {
log_error("Ignoring duplicate option, tagged %d.", tag);
return 0;
}
}
option = new(struct sd_dhcp_raw_option, 1);
if (!option)
return -ENOMEM;
option->tag = tag;
option->length = len;
option->data = memdup(data, len);
if (!option->data) {
free(option);
return -ENOMEM;
}
LIST_INSERT_BEFORE(options, lease->private_options, cur, option);
return 0;
}
int dhcp_lease_new(sd_dhcp_lease **ret) {
sd_dhcp_lease *lease;
@@ -634,6 +668,7 @@ int dhcp_lease_new(sd_dhcp_lease **ret) {
lease->router = INADDR_ANY;
lease->n_ref = REFCNT_INIT;
LIST_HEAD_INIT(lease->private_options);
*ret = lease;
return 0;
@@ -642,12 +677,12 @@ int dhcp_lease_new(sd_dhcp_lease **ret) {
int sd_dhcp_lease_save(sd_dhcp_lease *lease, const char *lease_file) {
_cleanup_free_ char *temp_path = NULL;
_cleanup_fclose_ FILE *f = NULL;
struct sd_dhcp_raw_option *option;
struct in_addr address;
const struct in_addr *addresses;
const uint8_t *client_id;
size_t client_id_len;
const uint8_t *client_id, *data;
size_t client_id_len, data_len;
const char *string;
uint8_t *data;
uint16_t mtu;
struct sd_dhcp_route *routes;
int r;
@@ -657,13 +692,13 @@ int sd_dhcp_lease_save(sd_dhcp_lease *lease, const char *lease_file) {
r = fopen_temporary(lease_file, &f, &temp_path);
if (r < 0)
goto finish;
goto fail;
fchmod(fileno(f), 0644);
r = sd_dhcp_lease_get_address(lease, &address);
if (r < 0)
goto finish;
goto fail;
fprintf(f,
"# This is private data. Do not parse.\n"
@@ -671,7 +706,7 @@ int sd_dhcp_lease_save(sd_dhcp_lease *lease, const char *lease_file) {
r = sd_dhcp_lease_get_netmask(lease, &address);
if (r < 0)
goto finish;
goto fail;
fprintf(f, "NETMASK=%s\n", inet_ntoa(address));
@@ -720,18 +755,6 @@ int sd_dhcp_lease_save(sd_dhcp_lease *lease, const char *lease_file) {
if (r >= 0)
serialize_dhcp_routes(f, "ROUTES", routes, r);
r = sd_dhcp_lease_get_vendor_specific(lease, &data);
if (r >= 0) {
_cleanup_free_ char *option_hex = NULL;
option_hex = hexmem(data, r);
if (!option_hex) {
r = -ENOMEM;
goto finish;
}
fprintf(f, "VENDOR_SPECIFIC=%s\n", option_hex);
}
r = sd_dhcp_lease_get_client_id(lease, &client_id, &client_id_len);
if (r >= 0) {
_cleanup_free_ char *client_id_hex = NULL;
@@ -739,26 +762,47 @@ int sd_dhcp_lease_save(sd_dhcp_lease *lease, const char *lease_file) {
client_id_hex = hexmem(client_id, client_id_len);
if (!client_id_hex) {
r = -ENOMEM;
goto finish;
goto fail;
}
fprintf(f, "CLIENTID=%s\n", client_id_hex);
}
r = 0;
r = sd_dhcp_lease_get_vendor_specific(lease, &data, &data_len);
if (r >= 0) {
_cleanup_free_ char *option_hex = NULL;
fflush(f);
if (ferror(f) || rename(temp_path, lease_file) < 0) {
r = -errno;
unlink(lease_file);
unlink(temp_path);
option_hex = hexmem(data, data_len);
if (!option_hex) {
r = -ENOMEM;
goto fail;
}
fprintf(f, "VENDOR_SPECIFIC=%s\n", option_hex);
}
finish:
LIST_FOREACH(options, option, lease->private_options) {
char key[strlen("OPTION_000")+1];
snprintf(key, sizeof(key), "OPTION_%"PRIu8, option->tag);
r = serialize_dhcp_option(f, key, option->data, option->length);
if (r < 0)
log_error_errno(r, "Failed to save lease data %s: %m", lease_file);
goto fail;
}
return r;
r = fflush_and_check(f);
if (r < 0)
goto fail;
if (rename(temp_path, lease_file) < 0) {
r = -errno;
goto fail;
}
return 0;
fail:
if (temp_path)
(void) unlink(temp_path);
return log_error_errno(r, "Failed to save lease data %s: %m", lease_file);
}
int sd_dhcp_lease_load(sd_dhcp_lease **ret, const char *lease_file) {
@@ -766,9 +810,12 @@ int sd_dhcp_lease_load(sd_dhcp_lease **ret, const char *lease_file) {
_cleanup_free_ char *address = NULL, *router = NULL, *netmask = NULL,
*server_address = NULL, *next_server = NULL,
*dns = NULL, *ntp = NULL, *mtu = NULL,
*routes = NULL, *client_id_hex = NULL;
*routes = NULL, *client_id_hex = NULL,
*vendor_specific_hex = NULL,
*options[DHCP_OPTION_PRIVATE_LAST -
DHCP_OPTION_PRIVATE_BASE + 1] = { NULL };
struct in_addr addr;
int r;
int r, i;
assert(lease_file);
assert(ret);
@@ -791,6 +838,38 @@ int sd_dhcp_lease_load(sd_dhcp_lease **ret, const char *lease_file) {
"ROOT_PATH", &lease->root_path,
"ROUTES", &routes,
"CLIENTID", &client_id_hex,
"VENDOR_SPECIFIC", &vendor_specific_hex,
"OPTION_224", &options[0],
"OPTION_225", &options[1],
"OPTION_226", &options[2],
"OPTION_227", &options[3],
"OPTION_228", &options[4],
"OPTION_229", &options[5],
"OPTION_230", &options[6],
"OPTION_231", &options[7],
"OPTION_232", &options[8],
"OPTION_233", &options[9],
"OPTION_234", &options[10],
"OPTION_235", &options[11],
"OPTION_236", &options[12],
"OPTION_237", &options[13],
"OPTION_238", &options[14],
"OPTION_239", &options[15],
"OPTION_240", &options[16],
"OPTION_241", &options[17],
"OPTION_242", &options[18],
"OPTION_243", &options[19],
"OPTION_244", &options[20],
"OPTION_245", &options[21],
"OPTION_246", &options[22],
"OPTION_247", &options[23],
"OPTION_248", &options[24],
"OPTION_249", &options[25],
"OPTION_250", &options[26],
"OPTION_251", &options[27],
"OPTION_252", &options[28],
"OPTION_253", &options[29],
"OPTION_254", &options[30],
NULL);
if (r < 0) {
if (r == -ENOENT)
@@ -865,13 +944,31 @@ int sd_dhcp_lease_load(sd_dhcp_lease **ret, const char *lease_file) {
}
if (client_id_hex) {
if (strlen (client_id_hex) % 2)
return -EINVAL;
r = deserialize_dhcp_option(&lease->client_id, &lease->client_id_len, client_id_hex);
if (r < 0)
return r;
}
lease->client_id = unhexmem (client_id_hex, strlen (client_id_hex));
if (!lease->client_id)
return -ENOMEM;
lease->client_id_len = strlen (client_id_hex) / 2;
if (vendor_specific_hex) {
r = deserialize_dhcp_option(&lease->vendor_specific, &lease->vendor_specific_len, vendor_specific_hex);
if (r < 0)
return r;
}
for (i = 0; i <= DHCP_OPTION_PRIVATE_LAST - DHCP_OPTION_PRIVATE_BASE; i++) {
_cleanup_free_ uint8_t *data = NULL;
size_t len;
if (!options[i])
continue;
r = deserialize_dhcp_option(&data, &len, options[i]);
if (r < 0)
return r;
r = dhcp_lease_insert_private_option(lease, DHCP_OPTION_PRIVATE_BASE + i, data, len);
if (r < 0)
return r;
}
*ret = lease;

View File

@@ -979,14 +979,9 @@ static int client_start(sd_dhcp6_client *client, enum DHCP6State state)
client->retransmit_time = 0;
client->retransmit_count = 0;
if (client->state == DHCP6_STATE_STOPPED) {
time_now = now(clock_boottime_or_monotonic());
} else {
r = sd_event_now(client->event, clock_boottime_or_monotonic(),
&time_now);
r = sd_event_now(client->event, clock_boottime_or_monotonic(), &time_now);
if (r < 0)
return r;
}
switch (state) {
case DHCP6_STATE_STOPPED:

View File

@@ -189,8 +189,7 @@ static void ipv4ll_set_next_wakeup(sd_ipv4ll *ll, int sec, int random_sec) {
if (random_sec)
next_timeout += random_u32() % (random_sec * USEC_PER_SEC);
if (sd_event_now(ll->event, clock_boottime_or_monotonic(), &time_now) < 0)
time_now = now(clock_boottime_or_monotonic());
assert_se(sd_event_now(ll->event, clock_boottime_or_monotonic(), &time_now) >= 0);
ll->next_wakeup = time_now + next_timeout;
ll->next_wakeup_valid = 1;
@@ -510,7 +509,7 @@ error:
}
bool sd_ipv4ll_is_running(sd_ipv4ll *ll) {
assert_return(ll, -EINVAL);
assert_return(ll, false);
return !IN_SET(ll->state, IPV4LL_STATE_INIT, IPV4LL_STATE_STOPPED);
}

View File

@@ -116,6 +116,68 @@ int dns_label_unescape(const char **name, char *dest, size_t sz) {
return r;
}
/* @label_terminal: terminal character of a label, updated to point to the terminal character of
* the previous label (always skipping one dot) or to NULL if there are no more
* labels. */
int dns_label_unescape_suffix(const char *name, const char **label_terminal, char *dest, size_t sz) {
const char *terminal;
int r;
assert(name);
assert(label_terminal);
assert(dest);
/* no more labels */
if (!*label_terminal) {
if (sz >= 1)
*dest = 0;
return 0;
}
assert(**label_terminal == '.' || **label_terminal == 0);
/* skip current terminal character */
terminal = *label_terminal - 1;
/* point name to the last label, and terminal to the preceding terminal symbol (or make it a NULL pointer) */
for (;;) {
if (terminal < name) {
/* reached the first label, so indicate that there are no more */
terminal = NULL;
break;
}
/* find the start of the last label */
if (*terminal == '.') {
const char *y;
unsigned slashes = 0;
for (y = terminal - 1; y >= name && *y == '\\'; y--)
slashes ++;
if (slashes % 2 == 0) {
/* the '.' was not escaped */
name = terminal + 1;
break;
} else {
terminal = y;
continue;
}
}
terminal --;
}
r = dns_label_unescape(&name, dest, sz);
if (r < 0)
return r;
*label_terminal = terminal;
return r;
}
int dns_label_escape(const char *p, size_t l, char **ret) {
_cleanup_free_ char *s = NULL;
char *q;
@@ -341,20 +403,23 @@ unsigned long dns_name_hash_func(const void *s, const uint8_t hash_key[HASH_KEY_
}
int dns_name_compare_func(const void *a, const void *b) {
const char *x = a, *y = b;
const char *x, *y;
int r, q, k, w;
assert(a);
assert(b);
x = (const char *) a + strlen(a);
y = (const char *) b + strlen(b);
for (;;) {
char la[DNS_LABEL_MAX+1], lb[DNS_LABEL_MAX+1];
if (*x == 0 && *y == 0)
if (x == NULL && y == NULL)
return 0;
r = dns_label_unescape(&x, la, sizeof(la));
q = dns_label_unescape(&y, lb, sizeof(lb));
r = dns_label_unescape_suffix(a, &x, la, sizeof(la));
q = dns_label_unescape_suffix(b, &y, lb, sizeof(lb));
if (r < 0 || q < 0)
return r - q;
@@ -467,6 +532,28 @@ int dns_name_endswith(const char *name, const char *suffix) {
}
}
int dns_name_between(const char *a, const char *b, const char *c) {
int n;
/* Determine if b is strictly greater than a and strictly smaller than c.
We consider the order of names to be circular, so that if a is
strictly greater than c, we consider b to be between them if it is
either greater than a or smaller than c. This is how the canonical
DNS name order used in NSEC records work. */
n = dns_name_compare_func(a, c);
if (n == 0)
return -EINVAL;
else if (n < 0)
/* a<---b--->c */
return dns_name_compare_func(a, b) < 0 &&
dns_name_compare_func(b, c) < 0;
else
/* <--b--c a--b--> */
return dns_name_compare_func(b, c) < 0 ||
dns_name_compare_func(a, b) < 0;
}
int dns_name_reverse(int family, const union in_addr_union *a, char **ret) {
const uint8_t *p;
int r;

View File

@@ -32,6 +32,7 @@
#define DNS_NAME_MAX 255
int dns_label_unescape(const char **name, char *dest, size_t sz);
int dns_label_unescape_suffix(const char *name, const char **label_end, char *dest, size_t sz);
int dns_label_escape(const char *p, size_t l, char **ret);
int dns_label_apply_idna(const char *encoded, size_t encoded_size, char *decoded, size_t decoded_max);
@@ -53,6 +54,7 @@ unsigned long dns_name_hash_func(const void *s, const uint8_t hash_key[HASH_KEY_
int dns_name_compare_func(const void *a, const void *b);
extern const struct hash_ops dns_name_hash_ops;
int dns_name_between(const char *a, const char *b, const char *c);
int dns_name_equal(const char *x, const char *y);
int dns_name_endswith(const char *name, const char *suffix);

View File

@@ -47,7 +47,8 @@ int sd_dhcp_lease_get_domainname(sd_dhcp_lease *lease, const char **domainname);
int sd_dhcp_lease_get_hostname(sd_dhcp_lease *lease, const char **hostname);
int sd_dhcp_lease_get_root_path(sd_dhcp_lease *lease, const char **root_path);
int sd_dhcp_lease_get_routes(sd_dhcp_lease *lease, struct sd_dhcp_route **routesgn);
int sd_dhcp_lease_get_vendor_specific(sd_dhcp_lease *lease, uint8_t **data);
int sd_dhcp_lease_get_vendor_specific(sd_dhcp_lease *lease, const uint8_t **data,
size_t *data_len);
int sd_dhcp_lease_get_client_id(sd_dhcp_lease *lease, const uint8_t **client_id,
size_t *client_id_len);