systemd: merge branch 'systemd' into master
This commit is contained in:
@@ -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;
|
||||
|
@@ -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;
|
||||
}
|
||||
|
@@ -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);
|
||||
|
@@ -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;
|
||||
|
@@ -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);
|
||||
|
||||
|
@@ -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) \
|
||||
|
||||
|
@@ -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) \
|
||||
|
@@ -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) {
|
||||
|
@@ -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 */
|
||||
|
@@ -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);
|
||||
|
@@ -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);
|
||||
|
||||
|
@@ -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,
|
||||
};
|
||||
|
@@ -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);
|
||||
}
|
||||
|
@@ -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);
|
||||
|
@@ -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;
|
||||
|
@@ -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:
|
||||
|
@@ -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);
|
||||
}
|
||||
|
@@ -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;
|
||||
|
@@ -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);
|
||||
|
||||
|
@@ -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);
|
||||
|
||||
|
Reference in New Issue
Block a user