Compare commits

..

No commits in common. "47b04ef6327bac408ed724f4e94967ed36b72877" and "f77d6ec9539fd87eb3ecad3a742ac684cc6dc5d2" have entirely different histories.

48 changed files with 532 additions and 740 deletions

3
TODO
View File

@ -4,9 +4,6 @@ Bugfixes:
manager or system manager can be always set. It would be better to reject
them when parsing config.
* userdbctl: "Password OK: yes" is shown even when there are no passwords
or the password is locked.
External:
* Fedora: add an rpmlint check that verifies that all unit files in the RPM are listed in %systemd_post macros.

View File

@ -415,7 +415,6 @@ Most socket unit settings are available to transient units.
✓ SocketMode=
✓ DirectoryMode=
✓ Accept=
✓ FlushPending=
✓ Writable=
✓ MaxConnections=
✓ MaxConnectionsPerSource=

View File

@ -3950,8 +3950,6 @@ node /org/freedesktop/systemd1/unit/avahi_2ddaemon_2esocket {
@org.freedesktop.DBus.Property.EmitsChangedSignal("false")
readonly u NRefused = ...;
@org.freedesktop.DBus.Property.EmitsChangedSignal("false")
readonly u FlushPending = ...;
@org.freedesktop.DBus.Property.EmitsChangedSignal("false")
readonly s FileDescriptorName = '...';
@org.freedesktop.DBus.Property.EmitsChangedSignal("const")
readonly i SocketProtocol = ...;
@ -5033,8 +5031,6 @@ node /org/freedesktop/systemd1/unit/avahi_2ddaemon_2esocket {
<variablelist class="dbus-property" generated="True" extra-ref="NRefused"/>
<variablelist class="dbus-property" generated="True" extra-ref="FlushPending"/>
<variablelist class="dbus-property" generated="True" extra-ref="FileDescriptorName"/>
<variablelist class="dbus-property" generated="True" extra-ref="SocketProtocol"/>
@ -5512,10 +5508,6 @@ node /org/freedesktop/systemd1/unit/avahi_2ddaemon_2esocket {
meaning as they have for the corresponding field of service units (see above). In addition to that,
the value <literal>service-failed-permanent</literal> indicates that the service of this socket failed
continuously.</para>
<para><varname>FlushPending</varname> specifies whether to flush the socket
just before entering the listening state. This setting only applies to sockets with
<varname>Accept=</varname> set to <literal>no</literal>.</para>
</refsect2>
</refsect1>

View File

@ -427,18 +427,6 @@
false, in read-only mode. Defaults to false.</para></listitem>
</varlistentry>
<varlistentry>
<term><varname>FlushPending=</varname></term>
<listitem><para>Takes a boolean argument. May only be used when
<option>Accept=no</option>. If yes, the socket's buffers are cleared after the
triggered service exited. This causes any pending data to be
flushed and any pending incoming connections to be rejected. If no, the
socket's buffers won't be cleared, permitting the service to handle any
pending connections after restart, which is the usually expected behaviour.
Defaults to <option>no</option>.
</para></listitem>
</varlistentry>
<varlistentry>
<term><varname>MaxConnections=</varname></term>
<listitem><para>The maximum number of connections to

View File

@ -59,13 +59,7 @@
user friendly, human readable output is generated; if <literal>table</literal> a minimal, tabular
output is generated; if <literal>json</literal> a JSON formatted output is generated. Defaults to
<literal>friendly</literal> if a user/group is specified on the command line,
<literal>table</literal> otherwise.</para>
<para>Note that most output formats do not show all available information. In particular,
<literal>classic</literal> and <literal>table</literal> show only the most important fields. Various
modes also do not show password hashes. Use <literal>json</literal> to view all fields, including
any authentication fields.</para>
</listitem>
<literal>table</literal> otherwise.</para></listitem>
</varlistentry>
<varlistentry>

View File

@ -161,21 +161,28 @@ int capability_ambient_set_apply(uint64_t set, bool also_inherit) {
return 0;
}
int capability_gain_cap_setpcap(cap_t *ret_before_caps) {
_cleanup_cap_free_ cap_t caps = NULL;
int capability_bounding_set_drop(uint64_t keep, bool right_now) {
_cleanup_cap_free_ cap_t before_cap = NULL, after_cap = NULL;
cap_flag_value_t fv;
caps = cap_get_proc();
if (!caps)
int r;
/* If we are run as PID 1 we will lack CAP_SETPCAP by default
* in the effective set (yes, the kernel drops that when
* executing init!), so get it back temporarily so that we can
* call PR_CAPBSET_DROP. */
before_cap = cap_get_proc();
if (!before_cap)
return -errno;
if (cap_get_flag(caps, CAP_SETPCAP, CAP_EFFECTIVE, &fv) < 0)
if (cap_get_flag(before_cap, CAP_SETPCAP, CAP_EFFECTIVE, &fv) < 0)
return -errno;
if (fv != CAP_SET) {
_cleanup_cap_free_ cap_t temp_cap = NULL;
static const cap_value_t v = CAP_SETPCAP;
temp_cap = cap_dup(caps);
temp_cap = cap_dup(before_cap);
if (!temp_cap)
return -errno;
@ -186,27 +193,8 @@ int capability_gain_cap_setpcap(cap_t *ret_before_caps) {
log_debug_errno(errno, "Can't acquire effective CAP_SETPCAP bit, ignoring: %m");
/* If we didn't manage to acquire the CAP_SETPCAP bit, we continue anyway, after all this just means
* we'll fail later, when we actually intend to drop some capabilities or try to set securebits. */
* we'll fail later, when we actually intend to drop some capabilities. */
}
if (ret_before_caps)
/* Return the capabilities as they have been before setting CAP_SETPCAP */
*ret_before_caps = TAKE_PTR(caps);
return 0;
}
int capability_bounding_set_drop(uint64_t keep, bool right_now) {
_cleanup_cap_free_ cap_t before_cap = NULL, after_cap = NULL;
int r;
/* If we are run as PID 1 we will lack CAP_SETPCAP by default
* in the effective set (yes, the kernel drops that when
* executing init!), so get it back temporarily so that we can
* call PR_CAPBSET_DROP. */
r = capability_gain_cap_setpcap(&before_cap);
if (r < 0)
return r;
after_cap = cap_dup(before_cap);
if (!after_cap)

View File

@ -14,7 +14,6 @@
unsigned cap_last_cap(void);
int have_effective_cap(int value);
int capability_gain_cap_setpcap(cap_t *return_caps);
int capability_bounding_set_drop(uint64_t keep, bool right_now);
int capability_bounding_set_drop_usermode(uint64_t keep);

View File

@ -75,7 +75,7 @@ int cescape_char(char c, char *buf) {
return buf - buf_old;
}
char* cescape_length(const char *s, size_t n) {
char *cescape_length(const char *s, size_t n) {
const char *f;
char *r, *t;
@ -96,7 +96,7 @@ char* cescape_length(const char *s, size_t n) {
return r;
}
char* cescape(const char *s) {
char *cescape(const char *s) {
assert(s);
return cescape_length(s, strlen(s));
@ -360,7 +360,7 @@ int cunescape_length_with_prefix(const char *s, size_t length, const char *prefi
return t - r;
}
char* xescape_full(const char *s, const char *bad, size_t console_width, bool eight_bits) {
char *xescape_full(const char *s, const char *bad, size_t console_width, bool eight_bits) {
char *ans, *t, *prev, *prev2;
const char *f;
@ -427,14 +427,14 @@ char* xescape_full(const char *s, const char *bad, size_t console_width, bool ei
return ans;
}
char* escape_non_printable_full(const char *str, size_t console_width, bool eight_bit) {
char *escape_non_printable_full(const char *str, size_t console_width, bool eight_bit) {
if (eight_bit)
return xescape_full(str, "", console_width, true);
else
return utf8_escape_non_printable_full(str, console_width);
}
char* octescape(const char *s, size_t len) {
char *octescape(const char *s, size_t len) {
char *r, *t;
const char *f;
@ -462,7 +462,7 @@ char* octescape(const char *s, size_t len) {
}
static char* strcpy_backslash_escaped(char *t, const char *s, const char *bad, bool escape_tab_nl) {
static char *strcpy_backslash_escaped(char *t, const char *s, const char *bad, bool escape_tab_nl) {
assert(bad);
for (; *s; s++) {
@ -481,7 +481,7 @@ static char* strcpy_backslash_escaped(char *t, const char *s, const char *bad, b
return t;
}
char* shell_escape(const char *s, const char *bad) {
char *shell_escape(const char *s, const char *bad) {
char *r, *t;
r = new(char, strlen(s)*2+1);

View File

@ -43,8 +43,8 @@ typedef enum EscapeStyle {
* syntax (a string enclosed in $'') instead of plain quotes. */
} EscapeStyle;
char* cescape(const char *s);
char* cescape_length(const char *s, size_t n);
char *cescape(const char *s);
char *cescape_length(const char *s, size_t n);
int cescape_char(char c, char *buf);
int cunescape_length_with_prefix(const char *s, size_t length, const char *prefix, UnescapeFlags flags, char **ret);
@ -56,12 +56,12 @@ static inline int cunescape(const char *s, UnescapeFlags flags, char **ret) {
}
int cunescape_one(const char *p, size_t length, char32_t *ret, bool *eight_bit, bool accept_nul);
char* xescape_full(const char *s, const char *bad, size_t console_width, bool eight_bits);
static inline char* xescape(const char *s, const char *bad) {
char *xescape_full(const char *s, const char *bad, size_t console_width, bool eight_bits);
static inline char *xescape(const char *s, const char *bad) {
return xescape_full(s, bad, SIZE_MAX, false);
}
char* octescape(const char *s, size_t len);
char* escape_non_printable_full(const char *str, size_t console_width, bool eight_bit);
char *octescape(const char *s, size_t len);
char *escape_non_printable_full(const char *str, size_t console_width, bool eight_bit);
char* shell_escape(const char *s, const char *bad);
char *shell_escape(const char *s, const char *bad);
char* shell_maybe_quote(const char *s, EscapeStyle style);

View File

@ -323,12 +323,12 @@ static void n_entries_dec(HashmapBase *h) {
h->n_direct_entries--;
}
static void* storage_ptr(HashmapBase *h) {
static void *storage_ptr(HashmapBase *h) {
return h->has_indirect ? h->indirect.storage
: h->direct.storage;
}
static uint8_t* hash_key(HashmapBase *h) {
static uint8_t *hash_key(HashmapBase *h) {
return h->has_indirect ? h->indirect.hash_key
: shared_hash_key;
}
@ -371,16 +371,16 @@ static void get_hash_key(uint8_t hash_key[HASH_KEY_SIZE], bool reuse_is_ok) {
memcpy(hash_key, current, sizeof(current));
}
static struct hashmap_base_entry* bucket_at(HashmapBase *h, unsigned idx) {
static struct hashmap_base_entry *bucket_at(HashmapBase *h, unsigned idx) {
return (struct hashmap_base_entry*)
((uint8_t*) storage_ptr(h) + idx * hashmap_type_info[h->type].entry_size);
}
static struct plain_hashmap_entry* plain_bucket_at(Hashmap *h, unsigned idx) {
static struct plain_hashmap_entry *plain_bucket_at(Hashmap *h, unsigned idx) {
return (struct plain_hashmap_entry*) bucket_at(HASHMAP_BASE(h), idx);
}
static struct ordered_hashmap_entry* ordered_bucket_at(OrderedHashmap *h, unsigned idx) {
static struct ordered_hashmap_entry *ordered_bucket_at(OrderedHashmap *h, unsigned idx) {
return (struct ordered_hashmap_entry*) bucket_at(HASHMAP_BASE(h), idx);
}
@ -388,13 +388,13 @@ static struct set_entry *set_bucket_at(Set *h, unsigned idx) {
return (struct set_entry*) bucket_at(HASHMAP_BASE(h), idx);
}
static struct ordered_hashmap_entry* bucket_at_swap(struct swap_entries *swap, unsigned idx) {
static struct ordered_hashmap_entry *bucket_at_swap(struct swap_entries *swap, unsigned idx) {
return &swap->e[idx - _IDX_SWAP_BEGIN];
}
/* Returns a pointer to the bucket at index idx.
* Understands real indexes and swap indexes, hence "_virtual". */
static struct hashmap_base_entry* bucket_at_virtual(HashmapBase *h, struct swap_entries *swap,
static struct hashmap_base_entry *bucket_at_virtual(HashmapBase *h, struct swap_entries *swap,
unsigned idx) {
if (idx < _IDX_SWAP_BEGIN)
return bucket_at(h, idx);
@ -405,7 +405,7 @@ static struct hashmap_base_entry* bucket_at_virtual(HashmapBase *h, struct swap_
assert_not_reached("Invalid index");
}
static dib_raw_t* dib_raw_ptr(HashmapBase *h) {
static dib_raw_t *dib_raw_ptr(HashmapBase *h) {
return (dib_raw_t*)
((uint8_t*) storage_ptr(h) + hashmap_type_info[h->type].entry_size * n_buckets(h));
}
@ -503,7 +503,7 @@ static unsigned prev_idx(HashmapBase *h, unsigned idx) {
return (n_buckets(h) + idx - 1U) % n_buckets(h);
}
static void* entry_value(HashmapBase *h, struct hashmap_base_entry *e) {
static void *entry_value(HashmapBase *h, struct hashmap_base_entry *e) {
switch (h->type) {
case HASHMAP_TYPE_PLAIN:
@ -730,12 +730,16 @@ bool _hashmap_iterate(HashmapBase *h, Iterator *i, void **value, const void **ke
return true;
}
bool set_iterate(const Set *s, Iterator *i, void **value) {
return _hashmap_iterate(HASHMAP_BASE((Set*) s), i, value, NULL);
}
#define HASHMAP_FOREACH_IDX(idx, h, i) \
for ((i) = ITERATOR_FIRST, (idx) = hashmap_iterate_entry((h), &(i)); \
(idx != IDX_NIL); \
(idx) = hashmap_iterate_entry((h), &(i)))
IteratedCache* _hashmap_iterated_cache_new(HashmapBase *h) {
IteratedCache *_hashmap_iterated_cache_new(HashmapBase *h) {
IteratedCache *cache;
assert(h);
@ -764,7 +768,7 @@ static void reset_direct_storage(HashmapBase *h) {
memset(p, DIB_RAW_INIT, sizeof(dib_raw_t) * hi->n_direct_buckets);
}
static struct HashmapBase* hashmap_base_new(const struct hash_ops *hash_ops, enum HashmapType type HASHMAP_DEBUG_PARAMS) {
static struct HashmapBase *hashmap_base_new(const struct hash_ops *hash_ops, enum HashmapType type HASHMAP_DEBUG_PARAMS) {
HashmapBase *h;
const struct hashmap_type_info *hi = &hashmap_type_info[type];
bool up;
@ -844,16 +848,6 @@ int _set_ensure_allocated(Set **s, const struct hash_ops *hash_ops HASHMAP_DEBU
return hashmap_base_ensure_allocated((HashmapBase**)s, hash_ops, HASHMAP_TYPE_SET HASHMAP_DEBUG_PASS_ARGS);
}
int _ordered_hashmap_ensure_put(OrderedHashmap **h, const struct hash_ops *hash_ops, const void *key, void *value HASHMAP_DEBUG_PARAMS) {
int r;
r = _ordered_hashmap_ensure_allocated(h, hash_ops HASHMAP_DEBUG_PASS_ARGS);
if (r < 0)
return r;
return ordered_hashmap_put(*h, key, value);
}
static void hashmap_free_no_clear(HashmapBase *h) {
assert(!h->has_indirect);
assert(h->n_direct_entries == 0);
@ -872,7 +866,7 @@ static void hashmap_free_no_clear(HashmapBase *h) {
free(h);
}
HashmapBase* _hashmap_free(HashmapBase *h, free_func_t default_free_key, free_func_t default_free_value) {
HashmapBase *_hashmap_free(HashmapBase *h, free_func_t default_free_key, free_func_t default_free_value) {
if (h) {
_hashmap_clear(h, default_free_key, default_free_value);
hashmap_free_no_clear(h);
@ -1329,7 +1323,7 @@ int hashmap_update(Hashmap *h, const void *key, void *value) {
return 0;
}
void* _hashmap_get(HashmapBase *h, const void *key) {
void *_hashmap_get(HashmapBase *h, const void *key) {
struct hashmap_base_entry *e;
unsigned hash, idx;
@ -1345,7 +1339,7 @@ void* _hashmap_get(HashmapBase *h, const void *key) {
return entry_value(h, e);
}
void* hashmap_get2(Hashmap *h, const void *key, void **key2) {
void *hashmap_get2(Hashmap *h, const void *key, void **key2) {
struct plain_hashmap_entry *e;
unsigned hash, idx;
@ -1374,7 +1368,7 @@ bool _hashmap_contains(HashmapBase *h, const void *key) {
return bucket_scan(h, hash, key) != IDX_NIL;
}
void* _hashmap_remove(HashmapBase *h, const void *key) {
void *_hashmap_remove(HashmapBase *h, const void *key) {
struct hashmap_base_entry *e;
unsigned hash, idx;
void *data;
@ -1394,7 +1388,7 @@ void* _hashmap_remove(HashmapBase *h, const void *key) {
return data;
}
void* hashmap_remove2(Hashmap *h, const void *key, void **rkey) {
void *hashmap_remove2(Hashmap *h, const void *key, void **rkey) {
struct plain_hashmap_entry *e;
unsigned hash, idx;
void *data;
@ -1512,7 +1506,7 @@ int hashmap_remove_and_replace(Hashmap *h, const void *old_key, const void *new_
return 0;
}
void* _hashmap_remove_value(HashmapBase *h, const void *key, void *value) {
void *_hashmap_remove_value(HashmapBase *h, const void *key, void *value) {
struct hashmap_base_entry *e;
unsigned hash, idx;
@ -1542,7 +1536,7 @@ static unsigned find_first_entry(HashmapBase *h) {
return hashmap_iterate_entry(h, &i);
}
void* _hashmap_first_key_and_value(HashmapBase *h, bool remove, void **ret_key) {
void *_hashmap_first_key_and_value(HashmapBase *h, bool remove, void **ret_key) {
struct hashmap_base_entry *e;
void *key, *data;
unsigned idx;
@ -1717,7 +1711,7 @@ int _hashmap_move_one(HashmapBase *h, HashmapBase *other, const void *key) {
return 0;
}
HashmapBase* _hashmap_copy(HashmapBase *h HASHMAP_DEBUG_PARAMS) {
HashmapBase *_hashmap_copy(HashmapBase *h HASHMAP_DEBUG_PARAMS) {
HashmapBase *copy;
int r;
@ -1745,7 +1739,7 @@ HashmapBase* _hashmap_copy(HashmapBase *h HASHMAP_DEBUG_PARAMS) {
return copy;
}
char** _hashmap_get_strv(HashmapBase *h) {
char **_hashmap_get_strv(HashmapBase *h) {
char **sv;
Iterator i;
unsigned idx, n;
@ -1762,7 +1756,7 @@ char** _hashmap_get_strv(HashmapBase *h) {
return sv;
}
void* ordered_hashmap_next(OrderedHashmap *h, const void *key) {
void *ordered_hashmap_next(OrderedHashmap *h, const void *key) {
struct ordered_hashmap_entry *e;
unsigned hash, idx;
@ -1967,7 +1961,7 @@ int iterated_cache_get(IteratedCache *cache, const void ***res_keys, const void
return 0;
}
IteratedCache* iterated_cache_free(IteratedCache *cache) {
IteratedCache *iterated_cache_free(IteratedCache *cache) {
if (cache) {
free(cache->keys.ptr);
free(cache->values.ptr);

View File

@ -83,8 +83,8 @@ typedef struct {
# define HASHMAP_DEBUG_PASS_ARGS
#endif
Hashmap* _hashmap_new(const struct hash_ops *hash_ops HASHMAP_DEBUG_PARAMS);
OrderedHashmap* _ordered_hashmap_new(const struct hash_ops *hash_ops HASHMAP_DEBUG_PARAMS);
Hashmap *_hashmap_new(const struct hash_ops *hash_ops HASHMAP_DEBUG_PARAMS);
OrderedHashmap *_ordered_hashmap_new(const struct hash_ops *hash_ops HASHMAP_DEBUG_PARAMS);
#define hashmap_new(ops) _hashmap_new(ops HASHMAP_DEBUG_SRC_ARGS)
#define ordered_hashmap_new(ops) _ordered_hashmap_new(ops HASHMAP_DEBUG_SRC_ARGS)
@ -96,39 +96,39 @@ OrderedHashmap* _ordered_hashmap_new(const struct hash_ops *hash_ops HASHMAP_DE
0; \
})
HashmapBase* _hashmap_free(HashmapBase *h, free_func_t default_free_key, free_func_t default_free_value);
static inline Hashmap* hashmap_free(Hashmap *h) {
HashmapBase *_hashmap_free(HashmapBase *h, free_func_t default_free_key, free_func_t default_free_value);
static inline Hashmap *hashmap_free(Hashmap *h) {
return (void*) _hashmap_free(HASHMAP_BASE(h), NULL, NULL);
}
static inline OrderedHashmap* ordered_hashmap_free(OrderedHashmap *h) {
static inline OrderedHashmap *ordered_hashmap_free(OrderedHashmap *h) {
return (void*) _hashmap_free(HASHMAP_BASE(h), NULL, NULL);
}
static inline Hashmap* hashmap_free_free(Hashmap *h) {
static inline Hashmap *hashmap_free_free(Hashmap *h) {
return (void*) _hashmap_free(HASHMAP_BASE(h), NULL, free);
}
static inline OrderedHashmap* ordered_hashmap_free_free(OrderedHashmap *h) {
static inline OrderedHashmap *ordered_hashmap_free_free(OrderedHashmap *h) {
return (void*) _hashmap_free(HASHMAP_BASE(h), NULL, free);
}
static inline Hashmap* hashmap_free_free_key(Hashmap *h) {
static inline Hashmap *hashmap_free_free_key(Hashmap *h) {
return (void*) _hashmap_free(HASHMAP_BASE(h), free, NULL);
}
static inline OrderedHashmap* ordered_hashmap_free_free_key(OrderedHashmap *h) {
static inline OrderedHashmap *ordered_hashmap_free_free_key(OrderedHashmap *h) {
return (void*) _hashmap_free(HASHMAP_BASE(h), free, NULL);
}
static inline Hashmap* hashmap_free_free_free(Hashmap *h) {
static inline Hashmap *hashmap_free_free_free(Hashmap *h) {
return (void*) _hashmap_free(HASHMAP_BASE(h), free, free);
}
static inline OrderedHashmap* ordered_hashmap_free_free_free(OrderedHashmap *h) {
static inline OrderedHashmap *ordered_hashmap_free_free_free(OrderedHashmap *h) {
return (void*) _hashmap_free(HASHMAP_BASE(h), free, free);
}
IteratedCache* iterated_cache_free(IteratedCache *cache);
IteratedCache *iterated_cache_free(IteratedCache *cache);
int iterated_cache_get(IteratedCache *cache, const void ***res_keys, const void ***res_values, unsigned *res_n_entries);
HashmapBase* _hashmap_copy(HashmapBase *h HASHMAP_DEBUG_PARAMS);
HashmapBase *_hashmap_copy(HashmapBase *h HASHMAP_DEBUG_PARAMS);
#define hashmap_copy(h) ((Hashmap*) _hashmap_copy(HASHMAP_BASE(h) HASHMAP_DEBUG_SRC_ARGS))
#define ordered_hashmap_copy(h) ((OrderedHashmap*) _hashmap_copy(HASHMAP_BASE(h) HASHMAP_DEBUG_SRC_ARGS))
@ -137,14 +137,11 @@ int _ordered_hashmap_ensure_allocated(OrderedHashmap **h, const struct hash_ops
#define hashmap_ensure_allocated(h, ops) _hashmap_ensure_allocated(h, ops HASHMAP_DEBUG_SRC_ARGS)
#define ordered_hashmap_ensure_allocated(h, ops) _ordered_hashmap_ensure_allocated(h, ops HASHMAP_DEBUG_SRC_ARGS)
int _ordered_hashmap_ensure_put(OrderedHashmap **h, const struct hash_ops *hash_ops, const void *key, void *value HASHMAP_DEBUG_PARAMS);
#define ordered_hashmap_ensure_put(s, ops, key, value) _ordered_hashmap_ensure_put(s, ops, key, value HASHMAP_DEBUG_SRC_ARGS)
IteratedCache* _hashmap_iterated_cache_new(HashmapBase *h);
static inline IteratedCache* hashmap_iterated_cache_new(Hashmap *h) {
IteratedCache *_hashmap_iterated_cache_new(HashmapBase *h);
static inline IteratedCache *hashmap_iterated_cache_new(Hashmap *h) {
return (IteratedCache*) _hashmap_iterated_cache_new(HASHMAP_BASE(h));
}
static inline IteratedCache* ordered_hashmap_iterated_cache_new(OrderedHashmap *h) {
static inline IteratedCache *ordered_hashmap_iterated_cache_new(OrderedHashmap *h) {
return (IteratedCache*) _hashmap_iterated_cache_new(HASHMAP_BASE(h));
}
@ -166,7 +163,7 @@ static inline int ordered_hashmap_replace(OrderedHashmap *h, const void *key, vo
return hashmap_replace(PLAIN_HASHMAP(h), key, value);
}
void* _hashmap_get(HashmapBase *h, const void *key);
void *_hashmap_get(HashmapBase *h, const void *key);
static inline void *hashmap_get(Hashmap *h, const void *key) {
return _hashmap_get(HASHMAP_BASE(h), key);
}
@ -174,7 +171,7 @@ static inline void *ordered_hashmap_get(OrderedHashmap *h, const void *key) {
return _hashmap_get(HASHMAP_BASE(h), key);
}
void* hashmap_get2(Hashmap *h, const void *key, void **rkey);
void *hashmap_get2(Hashmap *h, const void *key, void **rkey);
static inline void *ordered_hashmap_get2(OrderedHashmap *h, const void *key, void **rkey) {
return hashmap_get2(PLAIN_HASHMAP(h), key, rkey);
}
@ -187,7 +184,7 @@ static inline bool ordered_hashmap_contains(OrderedHashmap *h, const void *key)
return _hashmap_contains(HASHMAP_BASE(h), key);
}
void* _hashmap_remove(HashmapBase *h, const void *key);
void *_hashmap_remove(HashmapBase *h, const void *key);
static inline void *hashmap_remove(Hashmap *h, const void *key) {
return _hashmap_remove(HASHMAP_BASE(h), key);
}
@ -195,17 +192,17 @@ static inline void *ordered_hashmap_remove(OrderedHashmap *h, const void *key) {
return _hashmap_remove(HASHMAP_BASE(h), key);
}
void* hashmap_remove2(Hashmap *h, const void *key, void **rkey);
void *hashmap_remove2(Hashmap *h, const void *key, void **rkey);
static inline void *ordered_hashmap_remove2(OrderedHashmap *h, const void *key, void **rkey) {
return hashmap_remove2(PLAIN_HASHMAP(h), key, rkey);
}
void* _hashmap_remove_value(HashmapBase *h, const void *key, void *value);
void *_hashmap_remove_value(HashmapBase *h, const void *key, void *value);
static inline void *hashmap_remove_value(Hashmap *h, const void *key, void *value) {
return _hashmap_remove_value(HASHMAP_BASE(h), key, value);
}
static inline void* ordered_hashmap_remove_value(OrderedHashmap *h, const void *key, void *value) {
static inline void *ordered_hashmap_remove_value(OrderedHashmap *h, const void *key, void *value) {
return hashmap_remove_value(PLAIN_HASHMAP(h), key, value);
}
@ -391,13 +388,13 @@ static inline void *ordered_hashmap_first_key(OrderedHashmap *h) {
})
/* no hashmap_next */
void* ordered_hashmap_next(OrderedHashmap *h, const void *key);
void *ordered_hashmap_next(OrderedHashmap *h, const void *key);
char** _hashmap_get_strv(HashmapBase *h);
static inline char** hashmap_get_strv(Hashmap *h) {
char **_hashmap_get_strv(HashmapBase *h);
static inline char **hashmap_get_strv(Hashmap *h) {
return _hashmap_get_strv(HASHMAP_BASE(h));
}
static inline char** ordered_hashmap_get_strv(OrderedHashmap *h) {
static inline char **ordered_hashmap_get_strv(OrderedHashmap *h) {
return _hashmap_get_strv(HASHMAP_BASE(h));
}

View File

@ -5,7 +5,6 @@
#include <unistd.h>
#include "btrfs-util.h"
#include "fs-util.h"
#include "label.h"
#include "macro.h"
#include "selinux-util.h"
@ -46,27 +45,6 @@ int symlink_label(const char *old_path, const char *new_path) {
return mac_smack_fix(new_path, 0);
}
int symlink_atomic_label(const char *from, const char *to) {
int r;
assert(from);
assert(to);
r = mac_selinux_create_file_prepare(to, S_IFLNK);
if (r < 0)
return r;
if (symlink_atomic(from, to) < 0)
r = -errno;
mac_selinux_create_file_clear();
if (r < 0)
return r;
return mac_smack_fix(to, 0);
}
int mknod_label(const char *pathname, mode_t mode, dev_t dev) {
int r;

View File

@ -17,7 +17,6 @@ static inline int label_fix(const char *path, LabelFixFlags flags) {
int mkdir_label(const char *path, mode_t mode);
int mkdirat_label(int dirfd, const char *path, mode_t mode);
int symlink_label(const char *old_path, const char *new_path);
int symlink_atomic_label(const char *from, const char *to);
int mknod_label(const char *pathname, mode_t mode, dev_t dev);
int btrfs_subvol_make_label(const char *path);

View File

@ -4,27 +4,6 @@
#include "ordered-set.h"
#include "strv.h"
int _ordered_set_ensure_allocated(OrderedSet **s, const struct hash_ops *ops HASHMAP_DEBUG_PARAMS) {
if (*s)
return 0;
*s = _ordered_set_new(ops HASHMAP_DEBUG_PASS_ARGS);
if (!*s)
return -ENOMEM;
return 0;
}
int _ordered_set_ensure_put(OrderedSet **s, const struct hash_ops *ops, void *p HASHMAP_DEBUG_PARAMS) {
int r;
r = _ordered_set_ensure_allocated(s, ops HASHMAP_DEBUG_PASS_ARGS);
if (r < 0)
return r;
return ordered_set_put(*s, p);
}
int ordered_set_consume(OrderedSet *s, void *p) {
int r;

View File

@ -7,16 +7,20 @@
typedef struct OrderedSet OrderedSet;
static inline OrderedSet* _ordered_set_new(const struct hash_ops *ops HASHMAP_DEBUG_PARAMS) {
return (OrderedSet*) _ordered_hashmap_new(ops HASHMAP_DEBUG_PASS_ARGS);
static inline OrderedSet* ordered_set_new(const struct hash_ops *ops) {
return (OrderedSet*) ordered_hashmap_new(ops);
}
#define ordered_set_new(ops) _ordered_set_new(ops HASHMAP_DEBUG_SRC_ARGS)
int _ordered_set_ensure_allocated(OrderedSet **s, const struct hash_ops *ops HASHMAP_DEBUG_PARAMS);
#define ordered_set_ensure_allocated(s, ops) _ordered_set_ensure_allocated(s, ops HASHMAP_DEBUG_SRC_ARGS)
static inline int ordered_set_ensure_allocated(OrderedSet **s, const struct hash_ops *ops) {
if (*s)
return 0;
int _ordered_set_ensure_put(OrderedSet **s, const struct hash_ops *ops, void *p HASHMAP_DEBUG_PARAMS);
#define ordered_set_ensure_put(s, hash_ops, key) _ordered_set_ensure_put(s, hash_ops, key HASHMAP_DEBUG_SRC_ARGS)
*s = ordered_set_new(ops);
if (!*s)
return -ENOMEM;
return 0;
}
static inline OrderedSet* ordered_set_free(OrderedSet *s) {
return (OrderedSet*) ordered_hashmap_free((OrderedHashmap*) s);
@ -54,7 +58,7 @@ static inline void* ordered_set_steal_first(OrderedSet *s) {
return ordered_hashmap_steal_first((OrderedHashmap*) s);
}
static inline char** ordered_set_get_strv(OrderedSet *s) {
static inline char **ordered_set_get_strv(OrderedSet *s) {
return _hashmap_get_strv(HASHMAP_BASE((OrderedHashmap*) s));
}

View File

@ -13,14 +13,14 @@
0; \
})
Set* _set_new(const struct hash_ops *hash_ops HASHMAP_DEBUG_PARAMS);
Set *_set_new(const struct hash_ops *hash_ops HASHMAP_DEBUG_PARAMS);
#define set_new(ops) _set_new(ops HASHMAP_DEBUG_SRC_ARGS)
static inline Set* set_free(Set *s) {
static inline Set *set_free(Set *s) {
return (Set*) _hashmap_free(HASHMAP_BASE(s), NULL, NULL);
}
static inline Set* set_free_free(Set *s) {
static inline Set *set_free_free(Set *s) {
return (Set*) _hashmap_free(HASHMAP_BASE(s), free, NULL);
}
@ -77,9 +77,7 @@ static inline unsigned set_buckets(const Set *s) {
return _hashmap_buckets(HASHMAP_BASE((Set *) s));
}
static inline bool set_iterate(const Set *s, Iterator *i, void **value) {
return _hashmap_iterate(HASHMAP_BASE((Set*) s), i, value, NULL);
}
bool set_iterate(const Set *s, Iterator *i, void **value);
static inline void set_clear(Set *s) {
_hashmap_clear(HASHMAP_BASE(s), NULL, NULL);

View File

@ -150,22 +150,18 @@ bool utf8_is_printable_newline(const char* str, size_t length, bool allow_newlin
return true;
}
char *utf8_is_valid_n(const char *str, size_t len_bytes) {
/* Check if the string is composed of valid utf8 characters. If length len_bytes is given, stop after
* len_bytes. Otherwise, stop at NUL. */
char *utf8_is_valid(const char *str) {
const char *p;
assert(str);
for (const char *p = str; len_bytes != (size_t) -1 ? (size_t) (p - str) < len_bytes : *p != '\0'; ) {
p = str;
while (*p) {
int len;
if (_unlikely_(*p == '\0') && len_bytes != (size_t) -1)
return NULL; /* embedded NUL */
len = utf8_encoded_valid_unichar(p,
len_bytes != (size_t) -1 ? len_bytes - (p - str) : (size_t) -1);
if (_unlikely_(len < 0))
return NULL; /* invalid character */
len = utf8_encoded_valid_unichar(p, (size_t) -1);
if (len < 0)
return NULL;
p += len;
}

View File

@ -14,10 +14,7 @@
bool unichar_is_valid(char32_t c);
char *utf8_is_valid_n(const char *str, size_t len_bytes) _pure_;
static inline char *utf8_is_valid(const char *s) {
return utf8_is_valid_n(s, (size_t) -1);
}
char *utf8_is_valid(const char *s) _pure_;
char *ascii_is_valid(const char *s) _pure_;
char *ascii_is_valid_n(const char *str, size_t len);

View File

@ -291,7 +291,7 @@ int manager_varlink_init(Manager *m) {
return log_error_errno(r, "Failed to register varlink methods: %m");
if (!MANAGER_IS_TEST_RUN(m)) {
(void) mkdir_p_label("/run/systemd/userdb", 0755);
(void) mkdir_p("/run/systemd/userdb", 0755);
r = varlink_server_listen_address(s, "/run/systemd/userdb/io.systemd.DynamicUser", 0666);
if (r < 0)

View File

@ -86,7 +86,6 @@ const sd_bus_vtable bus_socket_vtable[] = {
SD_BUS_PROPERTY("SocketMode", "u", bus_property_get_mode, offsetof(Socket, socket_mode), SD_BUS_VTABLE_PROPERTY_CONST),
SD_BUS_PROPERTY("DirectoryMode", "u", bus_property_get_mode, offsetof(Socket, directory_mode), SD_BUS_VTABLE_PROPERTY_CONST),
SD_BUS_PROPERTY("Accept", "b", bus_property_get_bool, offsetof(Socket, accept), SD_BUS_VTABLE_PROPERTY_CONST),
SD_BUS_PROPERTY("FlushPending", "b", bus_property_get_bool, offsetof(Socket, flush_pending), SD_BUS_VTABLE_PROPERTY_CONST),
SD_BUS_PROPERTY("Writable", "b", bus_property_get_bool, offsetof(Socket, writable), SD_BUS_VTABLE_PROPERTY_CONST),
SD_BUS_PROPERTY("KeepAlive", "b", bus_property_get_bool, offsetof(Socket, keep_alive), SD_BUS_VTABLE_PROPERTY_CONST),
SD_BUS_PROPERTY("KeepAliveTimeUSec", "t", bus_property_get_usec, offsetof(Socket, keep_alive_time), SD_BUS_VTABLE_PROPERTY_CONST),
@ -180,9 +179,6 @@ static int bus_socket_set_transient_property(
if (streq(name, "Accept"))
return bus_set_transient_bool(u, name, &s->accept, message, flags, error);
if (streq(name, "FlushPending"))
return bus_set_transient_bool(u, name, &s->flush_pending, message, flags, error);
if (streq(name, "Writable"))
return bus_set_transient_bool(u, name, &s->writable, message, flags, error);

View File

@ -1077,42 +1077,26 @@ static int enforce_groups(gid_t gid, const gid_t *supplementary_gids, int ngids)
return 0;
}
static int set_securebits(int bits, int mask) {
int current, applied;
current = prctl(PR_GET_SECUREBITS);
if (current < 0)
return -errno;
/* Clear all securebits defined in mask and set bits */
applied = (current & ~mask) | bits;
if (current == applied)
return 0;
if (prctl(PR_SET_SECUREBITS, applied) < 0)
return -errno;
return 1;
}
static int enforce_user(const ExecContext *context, uid_t uid) {
assert(context);
int r;
if (!uid_is_valid(uid))
return 0;
/* Sets (but doesn't look up) the uid and make sure we keep the
* capabilities while doing so. For setting secure bits the capability CAP_SETPCAP is
* required, so we also need keep-caps in this case.
*/
* capabilities while doing so. */
if (context->capability_ambient_set != 0 || context->secure_bits != 0) {
if (context->capability_ambient_set != 0) {
/* First step: If we need to keep capabilities but
* drop privileges we need to make sure we keep our
* caps, while we drop privileges. */
if (uid != 0) {
/* Add KEEP_CAPS to the securebits */
r = set_securebits(1<<SECURE_KEEP_CAPS, 0);
if (r < 0)
return r;
int sb = context->secure_bits | 1<<SECURE_KEEP_CAPS;
if (prctl(PR_GET_SECUREBITS) != sb)
if (prctl(PR_SET_SECUREBITS, sb) < 0)
return -errno;
}
}
@ -4353,27 +4337,12 @@ static int exec_child(
#endif
/* PR_GET_SECUREBITS is not privileged, while PR_SET_SECUREBITS is. So to suppress potential EPERMs
* we'll try not to call PR_SET_SECUREBITS unless necessary. Setting securebits requires
* CAP_SETPCAP. */
if (prctl(PR_GET_SECUREBITS) != secure_bits) {
/* CAP_SETPCAP is required to set securebits. This capabilitiy is raised into the
* effective set here.
* The effective set is overwritten during execve with the following values:
* - ambient set (for non-root processes)
* - (inheritable | bounding) set for root processes)
*
* Hence there is no security impact to raise it in the effective set before execve
*/
r = capability_gain_cap_setpcap(NULL);
if (r < 0) {
*exit_status = EXIT_CAPABILITIES;
return log_unit_error_errno(unit, r, "Failed to gain CAP_SETPCAP for setting secure bits");
}
* we'll try not to call PR_SET_SECUREBITS unless necessary. */
if (prctl(PR_GET_SECUREBITS) != secure_bits)
if (prctl(PR_SET_SECUREBITS, secure_bits) < 0) {
*exit_status = EXIT_SECUREBITS;
return log_unit_error_errno(unit, errno, "Failed to set process secure bits: %m");
}
}
if (context_has_no_new_privileges(context))
if (prctl(PR_SET_NO_NEW_PRIVS, 1, 0, 0, 0) < 0) {

View File

@ -391,7 +391,6 @@ Socket.SocketGroup, config_parse_user_group_compat, 0,
Socket.SocketMode, config_parse_mode, 0, offsetof(Socket, socket_mode)
Socket.DirectoryMode, config_parse_mode, 0, offsetof(Socket, directory_mode)
Socket.Accept, config_parse_bool, 0, offsetof(Socket, accept)
Socket.FlushPending, config_parse_bool, 0, offsetof(Socket, flush_pending)
Socket.Writable, config_parse_bool, 0, offsetof(Socket, writable)
Socket.MaxConnections, config_parse_unsigned, 0, offsetof(Socket, max_connections)
Socket.MaxConnectionsPerSource, config_parse_unsigned, 0, offsetof(Socket, max_connections_per_source)

View File

@ -63,7 +63,6 @@
#include "ratelimit.h"
#include "rlimit-util.h"
#include "rm-rf.h"
#include "selinux-util.h"
#include "serialize.h"
#include "signal-util.h"
#include "socket-util.h"
@ -964,9 +963,9 @@ static int manager_setup_notify(Manager *m) {
(void) mkdir_parents_label(m->notify_socket, 0755);
(void) sockaddr_un_unlink(&sa.un);
r = mac_selinux_bind(fd, &sa.sa, sa_len);
r = bind(fd, &sa.sa, sa_len);
if (r < 0)
return log_error_errno(r, "bind(%s) failed: %m", m->notify_socket);
return log_error_errno(errno, "bind(%s) failed: %m", m->notify_socket);
r = setsockopt_int(fd, SOL_SOCKET, SO_PASSCRED, true);
if (r < 0)

View File

@ -72,7 +72,6 @@ static const UnitActiveState state_translation_table[_SOCKET_STATE_MAX] = {
static int socket_dispatch_io(sd_event_source *source, int fd, uint32_t revents, void *userdata);
static int socket_dispatch_timer(sd_event_source *source, usec_t usec, void *userdata);
static void flush_ports(Socket *s);
static void socket_init(Unit *u) {
Socket *s = SOCKET(u);
@ -670,11 +669,6 @@ static void socket_dump(Unit *u, FILE *f, const char *prefix) {
prefix, s->n_connections,
prefix, s->max_connections,
prefix, s->max_connections_per_source);
else
fprintf(f,
"%sFlushPending: %s\n",
prefix, yes_no(s->flush_pending));
if (s->priority >= 0)
fprintf(f,
@ -2207,11 +2201,6 @@ static void socket_enter_listening(Socket *s) {
int r;
assert(s);
if (!s->accept && s->flush_pending) {
log_unit_debug(UNIT(s), "Flushing socket before listening.");
flush_ports(s);
}
r = socket_watch_fds(s);
if (r < 0) {
log_unit_warning_errno(UNIT(s), r, "Failed to watch sockets: %m");

View File

@ -110,7 +110,6 @@ struct Socket {
bool accept;
bool remove_on_stop;
bool writable;
bool flush_pending;
int socket_protocol;

View File

@ -24,10 +24,10 @@
#include "fileio-label.h"
#include "fileio.h"
#include "format-util.h"
#include "fs-util.h"
#include "id128-util.h"
#include "io-util.h"
#include "install.h"
#include "label.h"
#include "load-dropin.h"
#include "load-fragment.h"
#include "log.h"
@ -5603,7 +5603,7 @@ static int unit_export_invocation_id(Unit *u) {
if (r < 0)
return log_unit_debug_errno(u, r, "Failed to get invocation path: %m");
r = symlink_atomic_label(u->invocation_id_string, p);
r = symlink_atomic(u->invocation_id_string, p);
if (r < 0)
return log_unit_debug_errno(u, r, "Failed to create invocation ID symlink %s: %m", p);

View File

@ -6,13 +6,13 @@
#include "env-util.h"
#include "errno-util.h"
#include "fd-util.h"
#include "group-record-nss.h"
#include "macro.h"
#include "nss-systemd.h"
#include "nss-util.h"
#include "pthread-util.h"
#include "signal-util.h"
#include "strv.h"
#include "user-record-nss.h"
#include "user-util.h"
#include "userdb-glue.h"
#include "userdb.h"

View File

@ -2,9 +2,9 @@
#include "env-util.h"
#include "fd-util.h"
#include "group-record-nss.h"
#include "nss-systemd.h"
#include "strv.h"
#include "user-record-nss.h"
#include "user-record.h"
#include "userdb-glue.h"
#include "userdb.h"

View File

@ -1956,7 +1956,6 @@ static int bus_append_socket_property(sd_bus_message *m, const char *field, cons
int r;
if (STR_IN_SET(field, "Accept",
"FlushPending",
"Writable",
"KeepAlive",
"NoDelay",

View File

@ -0,0 +1,219 @@
/* SPDX-License-Identifier: LGPL-2.1+ */
#include "errno-util.h"
#include "group-record-nss.h"
#include "libcrypt-util.h"
#include "strv.h"
int nss_group_to_group_record(
const struct group *grp,
const struct sgrp *sgrp,
GroupRecord **ret) {
_cleanup_(group_record_unrefp) GroupRecord *g = NULL;
int r;
assert(grp);
assert(ret);
if (isempty(grp->gr_name))
return -EINVAL;
if (sgrp && !streq_ptr(sgrp->sg_namp, grp->gr_name))
return -EINVAL;
g = group_record_new();
if (!g)
return -ENOMEM;
g->group_name = strdup(grp->gr_name);
if (!g->group_name)
return -ENOMEM;
g->members = strv_copy(grp->gr_mem);
if (!g->members)
return -ENOMEM;
g->gid = grp->gr_gid;
if (sgrp) {
if (hashed_password_valid(sgrp->sg_passwd)) {
g->hashed_password = strv_new(sgrp->sg_passwd);
if (!g->hashed_password)
return -ENOMEM;
}
r = strv_extend_strv(&g->members, sgrp->sg_mem, 1);
if (r < 0)
return r;
g->administrators = strv_copy(sgrp->sg_adm);
if (!g->administrators)
return -ENOMEM;
}
r = json_build(&g->json, JSON_BUILD_OBJECT(
JSON_BUILD_PAIR("groupName", JSON_BUILD_STRING(g->group_name)),
JSON_BUILD_PAIR("gid", JSON_BUILD_UNSIGNED(g->gid)),
JSON_BUILD_PAIR_CONDITION(!strv_isempty(g->members), "members", JSON_BUILD_STRV(g->members)),
JSON_BUILD_PAIR_CONDITION(!strv_isempty(g->hashed_password), "privileged", JSON_BUILD_OBJECT(JSON_BUILD_PAIR("hashedPassword", JSON_BUILD_STRV(g->hashed_password)))),
JSON_BUILD_PAIR_CONDITION(!strv_isempty(g->administrators), "administrators", JSON_BUILD_STRV(g->administrators))));
if (r < 0)
return r;
g->mask = USER_RECORD_REGULAR |
(!strv_isempty(g->hashed_password) ? USER_RECORD_PRIVILEGED : 0);
*ret = TAKE_PTR(g);
return 0;
}
int nss_sgrp_for_group(const struct group *grp, struct sgrp *ret_sgrp, char **ret_buffer) {
size_t buflen = 4096;
int r;
assert(grp);
assert(ret_sgrp);
assert(ret_buffer);
for (;;) {
_cleanup_free_ char *buf = NULL;
struct sgrp sgrp, *result;
buf = malloc(buflen);
if (!buf)
return -ENOMEM;
r = getsgnam_r(grp->gr_name, &sgrp, buf, buflen, &result);
if (r == 0) {
if (!result)
return -ESRCH;
*ret_sgrp = *result;
*ret_buffer = TAKE_PTR(buf);
return 0;
}
if (r < 0)
return -EIO; /* Weird, this should not return negative! */
if (r != ERANGE)
return -r;
if (buflen > SIZE_MAX / 2)
return -ERANGE;
buflen *= 2;
buf = mfree(buf);
}
}
int nss_group_record_by_name(
const char *name,
bool with_shadow,
GroupRecord **ret) {
_cleanup_free_ char *buf = NULL, *sbuf = NULL;
struct group grp, *result;
bool incomplete = false;
size_t buflen = 4096;
struct sgrp sgrp, *sresult = NULL;
int r;
assert(name);
assert(ret);
for (;;) {
buf = malloc(buflen);
if (!buf)
return -ENOMEM;
r = getgrnam_r(name, &grp, buf, buflen, &result);
if (r == 0) {
if (!result)
return -ESRCH;
break;
}
if (r < 0)
return log_debug_errno(SYNTHETIC_ERRNO(EIO), "getgrnam_r() returned a negative value");
if (r != ERANGE)
return -r;
if (buflen > SIZE_MAX / 2)
return -ERANGE;
buflen *= 2;
buf = mfree(buf);
}
if (with_shadow) {
r = nss_sgrp_for_group(result, &sgrp, &sbuf);
if (r < 0) {
log_debug_errno(r, "Failed to do shadow lookup for group %s, ignoring: %m", result->gr_name);
incomplete = ERRNO_IS_PRIVILEGE(r);
} else
sresult = &sgrp;
} else
incomplete = true;
r = nss_group_to_group_record(result, sresult, ret);
if (r < 0)
return r;
(*ret)->incomplete = incomplete;
return 0;
}
int nss_group_record_by_gid(
gid_t gid,
bool with_shadow,
GroupRecord **ret) {
_cleanup_free_ char *buf = NULL, *sbuf = NULL;
struct group grp, *result;
bool incomplete = false;
size_t buflen = 4096;
struct sgrp sgrp, *sresult = NULL;
int r;
assert(ret);
for (;;) {
buf = malloc(buflen);
if (!buf)
return -ENOMEM;
r = getgrgid_r(gid, &grp, buf, buflen, &result);
if (r == 0) {
if (!result)
return -ESRCH;
break;
}
if (r < 0)
return log_debug_errno(SYNTHETIC_ERRNO(EIO), "getgrgid_r() returned a negative value");
if (r != ERANGE)
return -r;
if (buflen > SIZE_MAX / 2)
return -ERANGE;
buflen *= 2;
buf = mfree(buf);
}
if (with_shadow) {
r = nss_sgrp_for_group(result, &sgrp, &sbuf);
if (r < 0) {
log_debug_errno(r, "Failed to do shadow lookup for group %s, ignoring: %m", result->gr_name);
incomplete = ERRNO_IS_PRIVILEGE(r);
} else
sresult = &sgrp;
} else
incomplete = true;
r = nss_group_to_group_record(result, sresult, ret);
if (r < 0)
return r;
(*ret)->incomplete = incomplete;
return 0;
}

View File

@ -0,0 +1,15 @@
/* SPDX-License-Identifier: LGPL-2.1+ */
#pragma once
#include <grp.h>
#include <gshadow.h>
#include "group-record.h"
/* Synthesize GroupRecord objects from NSS data */
int nss_group_to_group_record(const struct group *grp, const struct sgrp *sgrp, GroupRecord **ret);
int nss_sgrp_for_group(const struct group *grp, struct sgrp *ret_sgrp, char **ret_buffer);
int nss_group_record_by_name(const char *name, bool with_shadow, GroupRecord **ret);
int nss_group_record_by_gid(gid_t gid, bool with_shadow, GroupRecord **ret);

View File

@ -0,0 +1,79 @@
/* SPDX-License-Identifier: LGPL-2.1+ */
#include "format-util.h"
#include "group-record-show.h"
#include "strv.h"
#include "user-util.h"
#include "userdb.h"
void group_record_show(GroupRecord *gr, bool show_full_user_info) {
int r;
printf(" Group name: %s\n",
group_record_group_name_and_realm(gr));
printf(" Disposition: %s\n", user_disposition_to_string(group_record_disposition(gr)));
if (gr->last_change_usec != USEC_INFINITY) {
char buf[FORMAT_TIMESTAMP_MAX];
printf(" Last Change: %s\n", format_timestamp(buf, sizeof(buf), gr->last_change_usec));
}
if (gid_is_valid(gr->gid))
printf(" GID: " GID_FMT "\n", gr->gid);
if (show_full_user_info) {
_cleanup_(userdb_iterator_freep) UserDBIterator *iterator = NULL;
r = membershipdb_by_group(gr->group_name, 0, &iterator);
if (r < 0) {
errno = -r;
printf(" Members: (can't acquire: %m)");
} else {
const char *prefix = " Members:";
for (;;) {
_cleanup_free_ char *user = NULL;
r = membershipdb_iterator_get(iterator, &user, NULL);
if (r == -ESRCH)
break;
if (r < 0) {
errno = -r;
printf("%s (can't iterate: %m\n", prefix);
break;
}
printf("%s %s\n", prefix, user);
prefix = " ";
}
}
} else {
const char *prefix = " Members:";
char **i;
STRV_FOREACH(i, gr->members) {
printf("%s %s\n", prefix, *i);
prefix = " ";
}
}
if (!strv_isempty(gr->administrators)) {
const char *prefix = " Admins:";
char **i;
STRV_FOREACH(i, gr->administrators) {
printf("%s %s\n", prefix, *i);
prefix = " ";
}
}
if (gr->description && !streq(gr->description, gr->group_name))
printf(" Description: %s\n", gr->description);
if (!strv_isempty(gr->hashed_password))
printf(" Passwords: %zu\n", strv_length(gr->hashed_password));
if (gr->service)
printf(" Service: %s\n", gr->service);
}

View File

@ -0,0 +1,6 @@
/* SPDX-License-Identifier: LGPL-2.1+ */
#pragma once
#include "group-record.h"
void group_record_show(GroupRecord *gr, bool show_full_user_info);

View File

@ -405,9 +405,6 @@ int json_variant_new_stringn(JsonVariant **ret, const char *s, size_t n) {
return 0;
}
if (!utf8_is_valid_n(s, n)) /* JSON strings must be valid UTF-8 */
return -EUCLEAN;
r = json_variant_new(&v, JSON_VARIANT_STRING, n + 1);
if (r < 0)
return r;
@ -639,13 +636,9 @@ int json_variant_new_array_strv(JsonVariant **ret, char **l) {
return r;
w->is_reference = true;
} else {
if (!utf8_is_valid_n(l[v->n_elements], k)) /* JSON strings must be valid UTF-8 */
return -EUCLEAN;
} else
memcpy(w->string, l[v->n_elements], k+1);
}
}
v->normalized = true;
@ -1489,58 +1482,6 @@ static int print_source(FILE *f, JsonVariant *v, JsonFormatFlags flags, bool whi
return 0;
}
static void json_format_string(FILE *f, const char *q, JsonFormatFlags flags) {
assert(q);
fputc('"', f);
if (flags & JSON_FORMAT_COLOR)
fputs(ANSI_GREEN, f);
for (; *q; q++)
switch (*q) {
case '"':
fputs("\\\"", f);
break;
case '\\':
fputs("\\\\", f);
break;
case '\b':
fputs("\\b", f);
break;
case '\f':
fputs("\\f", f);
break;
case '\n':
fputs("\\n", f);
break;
case '\r':
fputs("\\r", f);
break;
case '\t':
fputs("\\t", f);
break;
default:
if ((signed char) *q >= 0 && *q < ' ')
fprintf(f, "\\u%04x", *q);
else
fputc(*q, f);
break;
}
if (flags & JSON_FORMAT_COLOR)
fputs(ANSI_NORMAL, f);
fputc('"', f);
}
static int json_format(FILE *f, JsonVariant *v, JsonFormatFlags flags, const char *prefix) {
int r;
@ -1613,10 +1554,62 @@ static int json_format(FILE *f, JsonVariant *v, JsonFormatFlags flags, const cha
fputs(ANSI_NORMAL, f);
break;
case JSON_VARIANT_STRING:
json_format_string(f, json_variant_string(v), flags);
case JSON_VARIANT_STRING: {
const char *q;
fputc('"', f);
if (flags & JSON_FORMAT_COLOR)
fputs(ANSI_GREEN, f);
for (q = json_variant_string(v); *q; q++) {
switch (*q) {
case '"':
fputs("\\\"", f);
break;
case '\\':
fputs("\\\\", f);
break;
case '\b':
fputs("\\b", f);
break;
case '\f':
fputs("\\f", f);
break;
case '\n':
fputs("\\n", f);
break;
case '\r':
fputs("\\r", f);
break;
case '\t':
fputs("\\t", f);
break;
default:
if ((signed char) *q >= 0 && *q < ' ')
fprintf(f, "\\u%04x", *q);
else
fputc(*q, f);
break;
}
}
if (flags & JSON_FORMAT_COLOR)
fputs(ANSI_NORMAL, f);
fputc('"', f);
break;
}
case JSON_VARIANT_ARRAY: {
size_t i, n;

View File

@ -74,18 +74,13 @@ int make_salt(char **ret) {
#endif
}
bool looks_like_hashed_password(const char *s) {
/* Returns false if the specified string is certainly not a hashed UNIX password. crypt(5) lists
* various hashing methods. We only reject (return false) strings which are documented to have
* different meanings.
*
* In particular, we allow locked passwords, i.e. strings starting with "!", including just "!",
* i.e. the locked empty password. See also fc58c0c7bf7e4f525b916e3e5be0de2307fef04e.
*/
if (!s)
bool hashed_password_valid(const char *s) {
/* Returns true if the specified string is a 'valid' hashed UNIX password, i.e. if starts with '$' or
* with '!$' (the latter being a valid, yet locked password). */
if (isempty(s))
return false;
s += strspn(s, "!"); /* Skip (possibly duplicated) locking prefix */
return !STR_IN_SET(s, "x", "*");
return STARTSWITH_SET(s, "$", "!$");
}

View File

@ -19,4 +19,4 @@
int make_salt(char **ret);
bool looks_like_hashed_password(const char *s);
bool hashed_password_valid(const char *s);

View File

@ -113,6 +113,10 @@ shared_sources = files('''
geneve-util.h
gpt.c
gpt.h
group-record-nss.c
group-record-nss.h
group-record-show.c
group-record-show.h
group-record.c
group-record.h
id128-print.c

View File

@ -6,35 +6,10 @@
#include "strv.h"
#include "user-record-nss.h"
#include "user-util.h"
#include "utf8.h"
#define SET_IF(field, condition, value, fallback) \
field = (condition) ? (value) : (fallback)
static inline const char* utf8_only(const char *s) {
return s && utf8_is_valid(s) ? s : NULL;
}
static inline int strv_extend_strv_utf8_only(char ***dst, char **src, bool filter_duplicates) {
_cleanup_free_ char **t = NULL;
size_t l, j = 0;
/* First, do a shallow copy of s, filtering for only valid utf-8 strings */
l = strv_length(src);
t = new(char*, l + 1);
if (!t)
return -ENOMEM;
for (size_t i = 0; i < l; i++)
if (utf8_is_valid(src[i]))
t[j++] = src[i];
if (j == 0)
return 0;
t[j] = NULL;
return strv_extend_strv(dst, t, filter_duplicates);
}
int nss_passwd_to_user_record(
const struct passwd *pwd,
const struct spwd *spwd,
@ -80,19 +55,18 @@ int nss_passwd_to_user_record(
free_and_replace(hr->real_name, mangled);
}
r = free_and_strdup(&hr->home_directory, utf8_only(empty_to_null(pwd->pw_dir)));
r = free_and_strdup(&hr->home_directory, empty_to_null(pwd->pw_dir));
if (r < 0)
return r;
r = free_and_strdup(&hr->shell, utf8_only(empty_to_null(pwd->pw_shell)));
r = free_and_strdup(&hr->shell, empty_to_null(pwd->pw_shell));
if (r < 0)
return r;
hr->uid = pwd->pw_uid;
hr->gid = pwd->pw_gid;
if (spwd &&
looks_like_hashed_password(utf8_only(spwd->sp_pwdp))) { /* Ignore locked, disabled, and mojibake passwords */
if (spwd && hashed_password_valid(spwd->sp_pwdp)) {
strv_free_erase(hr->hashed_password);
hr->hashed_password = strv_new(spwd->sp_pwdp);
if (!hr->hashed_password)
@ -316,216 +290,3 @@ int nss_user_record_by_uid(
(*ret)->incomplete = incomplete;
return 0;
}
int nss_group_to_group_record(
const struct group *grp,
const struct sgrp *sgrp,
GroupRecord **ret) {
_cleanup_(group_record_unrefp) GroupRecord *g = NULL;
int r;
assert(grp);
assert(ret);
if (isempty(grp->gr_name))
return -EINVAL;
if (sgrp && !streq_ptr(sgrp->sg_namp, grp->gr_name))
return -EINVAL;
g = group_record_new();
if (!g)
return -ENOMEM;
g->group_name = strdup(grp->gr_name);
if (!g->group_name)
return -ENOMEM;
r = strv_extend_strv_utf8_only(&g->members, grp->gr_mem, false);
if (r < 0)
return r;
g->gid = grp->gr_gid;
if (sgrp) {
if (looks_like_hashed_password(utf8_only(sgrp->sg_passwd))) {
g->hashed_password = strv_new(sgrp->sg_passwd);
if (!g->hashed_password)
return -ENOMEM;
}
r = strv_extend_strv_utf8_only(&g->members, sgrp->sg_mem, true);
if (r < 0)
return r;
r = strv_extend_strv_utf8_only(&g->administrators, sgrp->sg_adm, false);
if (r < 0)
return r;
}
r = json_build(&g->json, JSON_BUILD_OBJECT(
JSON_BUILD_PAIR("groupName", JSON_BUILD_STRING(g->group_name)),
JSON_BUILD_PAIR("gid", JSON_BUILD_UNSIGNED(g->gid)),
JSON_BUILD_PAIR_CONDITION(!strv_isempty(g->members), "members", JSON_BUILD_STRV(g->members)),
JSON_BUILD_PAIR_CONDITION(!strv_isempty(g->hashed_password), "privileged", JSON_BUILD_OBJECT(JSON_BUILD_PAIR("hashedPassword", JSON_BUILD_STRV(g->hashed_password)))),
JSON_BUILD_PAIR_CONDITION(!strv_isempty(g->administrators), "administrators", JSON_BUILD_STRV(g->administrators))));
if (r < 0)
return r;
g->mask = USER_RECORD_REGULAR |
(!strv_isempty(g->hashed_password) ? USER_RECORD_PRIVILEGED : 0);
*ret = TAKE_PTR(g);
return 0;
}
int nss_sgrp_for_group(const struct group *grp, struct sgrp *ret_sgrp, char **ret_buffer) {
size_t buflen = 4096;
int r;
assert(grp);
assert(ret_sgrp);
assert(ret_buffer);
for (;;) {
_cleanup_free_ char *buf = NULL;
struct sgrp sgrp, *result;
buf = malloc(buflen);
if (!buf)
return -ENOMEM;
r = getsgnam_r(grp->gr_name, &sgrp, buf, buflen, &result);
if (r == 0) {
if (!result)
return -ESRCH;
*ret_sgrp = *result;
*ret_buffer = TAKE_PTR(buf);
return 0;
}
if (r < 0)
return -EIO; /* Weird, this should not return negative! */
if (r != ERANGE)
return -r;
if (buflen > SIZE_MAX / 2)
return -ERANGE;
buflen *= 2;
buf = mfree(buf);
}
}
int nss_group_record_by_name(
const char *name,
bool with_shadow,
GroupRecord **ret) {
_cleanup_free_ char *buf = NULL, *sbuf = NULL;
struct group grp, *result;
bool incomplete = false;
size_t buflen = 4096;
struct sgrp sgrp, *sresult = NULL;
int r;
assert(name);
assert(ret);
for (;;) {
buf = malloc(buflen);
if (!buf)
return -ENOMEM;
r = getgrnam_r(name, &grp, buf, buflen, &result);
if (r == 0) {
if (!result)
return -ESRCH;
break;
}
if (r < 0)
return log_debug_errno(SYNTHETIC_ERRNO(EIO), "getgrnam_r() returned a negative value");
if (r != ERANGE)
return -r;
if (buflen > SIZE_MAX / 2)
return -ERANGE;
buflen *= 2;
buf = mfree(buf);
}
if (with_shadow) {
r = nss_sgrp_for_group(result, &sgrp, &sbuf);
if (r < 0) {
log_debug_errno(r, "Failed to do shadow lookup for group %s, ignoring: %m", result->gr_name);
incomplete = ERRNO_IS_PRIVILEGE(r);
} else
sresult = &sgrp;
} else
incomplete = true;
r = nss_group_to_group_record(result, sresult, ret);
if (r < 0)
return r;
(*ret)->incomplete = incomplete;
return 0;
}
int nss_group_record_by_gid(
gid_t gid,
bool with_shadow,
GroupRecord **ret) {
_cleanup_free_ char *buf = NULL, *sbuf = NULL;
struct group grp, *result;
bool incomplete = false;
size_t buflen = 4096;
struct sgrp sgrp, *sresult = NULL;
int r;
assert(ret);
for (;;) {
buf = malloc(buflen);
if (!buf)
return -ENOMEM;
r = getgrgid_r(gid, &grp, buf, buflen, &result);
if (r == 0) {
if (!result)
return -ESRCH;
break;
}
if (r < 0)
return log_debug_errno(SYNTHETIC_ERRNO(EIO), "getgrgid_r() returned a negative value");
if (r != ERANGE)
return -r;
if (buflen > SIZE_MAX / 2)
return -ERANGE;
buflen *= 2;
buf = mfree(buf);
}
if (with_shadow) {
r = nss_sgrp_for_group(result, &sgrp, &sbuf);
if (r < 0) {
log_debug_errno(r, "Failed to do shadow lookup for group %s, ignoring: %m", result->gr_name);
incomplete = ERRNO_IS_PRIVILEGE(r);
} else
sresult = &sgrp;
} else
incomplete = true;
r = nss_group_to_group_record(result, sresult, ret);
if (r < 0)
return r;
(*ret)->incomplete = incomplete;
return 0;
}

View File

@ -1,24 +1,15 @@
/* SPDX-License-Identifier: LGPL-2.1+ */
#pragma once
#include <grp.h>
#include <gshadow.h>
#include <pwd.h>
#include <shadow.h>
#include "group-record.h"
#include "user-record.h"
/* Synthesize UserRecord and GroupRecord objects from NSS data */
/* Synthesizes a UserRecord object from NSS data */
int nss_passwd_to_user_record(const struct passwd *pwd, const struct spwd *spwd, UserRecord **ret);
int nss_spwd_for_passwd(const struct passwd *pwd, struct spwd *ret_spwd, char **ret_buffer);
int nss_user_record_by_name(const char *name, bool with_shadow, UserRecord **ret);
int nss_user_record_by_uid(uid_t uid, bool with_shadow, UserRecord **ret);
int nss_group_to_group_record(const struct group *grp, const struct sgrp *sgrp, GroupRecord **ret);
int nss_sgrp_for_group(const struct group *grp, struct sgrp *ret_sgrp, char **ret_buffer);
int nss_group_record_by_name(const char *name, bool with_shadow, GroupRecord **ret);
int nss_group_record_by_gid(gid_t gid, bool with_shadow, GroupRecord **ret);

View File

@ -2,6 +2,7 @@
#include "format-util.h"
#include "fs-util.h"
#include "group-record.h"
#include "process-util.h"
#include "rlimit-util.h"
#include "strv.h"
@ -505,75 +506,3 @@ void user_record_show(UserRecord *hr, bool show_full_group_info) {
if (hr->service)
printf(" Service: %s\n", hr->service);
}
void group_record_show(GroupRecord *gr, bool show_full_user_info) {
int r;
printf(" Group name: %s\n",
group_record_group_name_and_realm(gr));
printf(" Disposition: %s\n", user_disposition_to_string(group_record_disposition(gr)));
if (gr->last_change_usec != USEC_INFINITY) {
char buf[FORMAT_TIMESTAMP_MAX];
printf(" Last Change: %s\n", format_timestamp(buf, sizeof(buf), gr->last_change_usec));
}
if (gid_is_valid(gr->gid))
printf(" GID: " GID_FMT "\n", gr->gid);
if (show_full_user_info) {
_cleanup_(userdb_iterator_freep) UserDBIterator *iterator = NULL;
r = membershipdb_by_group(gr->group_name, 0, &iterator);
if (r < 0) {
errno = -r;
printf(" Members: (can't acquire: %m)");
} else {
const char *prefix = " Members:";
for (;;) {
_cleanup_free_ char *user = NULL;
r = membershipdb_iterator_get(iterator, &user, NULL);
if (r == -ESRCH)
break;
if (r < 0) {
errno = -r;
printf("%s (can't iterate: %m\n", prefix);
break;
}
printf("%s %s\n", prefix, user);
prefix = " ";
}
}
} else {
const char *prefix = " Members:";
char **i;
STRV_FOREACH(i, gr->members) {
printf("%s %s\n", prefix, *i);
prefix = " ";
}
}
if (!strv_isempty(gr->administrators)) {
const char *prefix = " Admins:";
char **i;
STRV_FOREACH(i, gr->administrators) {
printf("%s %s\n", prefix, *i);
prefix = " ";
}
}
if (gr->description && !streq(gr->description, gr->group_name))
printf(" Description: %s\n", gr->description);
if (!strv_isempty(gr->hashed_password))
printf(" Passwords: %zu\n", strv_length(gr->hashed_password));
if (gr->service)
printf(" Service: %s\n", gr->service);
}

View File

@ -2,9 +2,7 @@
#pragma once
#include "user-record.h"
#include "group-record.h"
const char *user_record_state_color(const char *state);
void user_record_show(UserRecord *hr, bool show_full_group_info);
void group_record_show(GroupRecord *gr, bool show_full_user_info);

View File

@ -6,6 +6,7 @@
#include "dlfcn-util.h"
#include "errno-util.h"
#include "fd-util.h"
#include "group-record-nss.h"
#include "missing_syscall.h"
#include "parse-util.h"
#include "set.h"

View File

@ -9,7 +9,6 @@
#include "io-util.h"
#include "list.h"
#include "process-util.h"
#include "selinux-util.h"
#include "set.h"
#include "socket-util.h"
#include "string-table.h"
@ -580,17 +579,11 @@ static int varlink_parse_message(Varlink *v) {
sz = e - begin + 1;
varlink_log(v, "New incoming message: %s", begin); /* FIXME: should we output the whole message here before validation?
* This may produce a non-printable journal entry if the message
* is invalid. We may also expose privileged information. */
varlink_log(v, "New incoming message: %s", begin);
r = json_parse(begin, 0, &v->current, NULL, NULL);
if (r < 0) {
/* If we encounter a parse failure flush all data. We cannot possibly recover from this,
* hence drop all buffered data now. */
v->input_buffer_index = v->input_buffer_size = v->input_buffer_unscanned = 0;
return varlink_log_errno(v, r, "Failed to parse JSON: %m");
}
if (r < 0)
return r;
v->input_buffer_size -= sz;
@ -2250,11 +2243,9 @@ int varlink_server_listen_address(VarlinkServer *s, const char *address, mode_t
(void) sockaddr_un_unlink(&sockaddr.un);
RUN_WITH_UMASK(~m & 0777) {
r = mac_selinux_bind(fd, &sockaddr.sa, sockaddr_len);
if (r < 0)
return r;
}
RUN_WITH_UMASK(~m & 0777)
if (bind(fd, &sockaddr.sa, sockaddr_len) < 0)
return -errno;
if (listen(fd, SOMAXCONN) < 0)
return -errno;

View File

@ -3,7 +3,6 @@
#include <math.h>
#include "alloc-util.h"
#include "escape.h"
#include "fd-util.h"
#include "fileio.h"
#include "json-internal.h"
@ -18,10 +17,6 @@ static void test_tokenizer(const char *data, ...) {
void *state = NULL;
va_list ap;
_cleanup_free_ char *cdata;
assert_se(cdata = cescape(data));
log_info("/* %s data=\"%s\" */", __func__, cdata);
va_start(ap, data);
for (;;) {
@ -87,10 +82,6 @@ static void test_variant(const char *data, Test test) {
_cleanup_free_ char *s = NULL;
int r;
_cleanup_free_ char *cdata;
assert_se(cdata = cescape(data));
log_info("/* %s data=\"%s\" */", __func__, cdata);
r = json_parse(data, 0, &v, NULL, NULL);
assert_se(r == 0);
assert_se(v);
@ -149,8 +140,6 @@ static void test_1(JsonVariant *v) {
JsonVariant *p, *q;
unsigned i;
log_info("/* %s */", __func__);
/* 3 keys + 3 values */
assert_se(json_variant_elements(v) == 6);
@ -184,8 +173,6 @@ static void test_1(JsonVariant *v) {
static void test_2(JsonVariant *v) {
JsonVariant *p, *q;
log_info("/* %s */", __func__);
/* 2 keys + 2 values */
assert_se(json_variant_elements(v) == 4);
@ -229,12 +216,13 @@ static void test_2(JsonVariant *v) {
}
static void test_zeroes(JsonVariant *v) {
size_t i;
/* Make sure zero is how we expect it. */
log_info("/* %s */", __func__);
assert_se(json_variant_elements(v) == 13);
for (size_t i = 0; i < json_variant_elements(v); i++) {
for (i = 0; i < json_variant_elements(v); i++) {
JsonVariant *w;
size_t j;
@ -267,8 +255,6 @@ static void test_zeroes(JsonVariant *v) {
}
static void test_build(void) {
log_info("/* %s */", __func__);
_cleanup_(json_variant_unrefp) JsonVariant *a = NULL, *b = NULL;
_cleanup_free_ char *s = NULL, *t = NULL;
@ -369,8 +355,6 @@ static void test_source(void) {
"false, 7.5, {} ]\n"
"}\n";
log_info("/* %s */", __func__);
_cleanup_fclose_ FILE *f = NULL;
_cleanup_(json_variant_unrefp) JsonVariant *v = NULL;
@ -392,16 +376,15 @@ static void test_source(void) {
}
static void test_depth(void) {
log_info("/* %s */", __func__);
_cleanup_(json_variant_unrefp) JsonVariant *v = NULL;
unsigned i;
int r;
v = JSON_VARIANT_STRING_CONST("start");
/* Let's verify that the maximum depth checks work */
for (unsigned i = 0;; i++) {
for (i = 0;; i++) {
_cleanup_(json_variant_unrefp) JsonVariant *w = NULL;
assert_se(i <= UINT16_MAX);
@ -432,8 +415,6 @@ static void test_depth(void) {
}
static void test_normalize(void) {
log_info("/* %s */", __func__);
_cleanup_(json_variant_unrefp) JsonVariant *v = NULL, *w = NULL;
_cleanup_free_ char *t = NULL;
@ -478,13 +459,12 @@ static void test_normalize(void) {
}
static void test_bisect(void) {
log_info("/* %s */", __func__);
_cleanup_(json_variant_unrefp) JsonVariant *v = NULL;
char c;
/* Tests the bisection logic in json_variant_by_key() */
for (char c = 'z'; c >= 'a'; c--) {
for (c = 'z'; c >= 'a'; c--) {
if ((c % 3) == 0)
continue;
@ -504,7 +484,7 @@ static void test_bisect(void) {
json_variant_dump(v, JSON_FORMAT_COLOR|JSON_FORMAT_PRETTY, NULL, NULL);
for (char c = 'a'; c <= 'z'; c++) {
for (c = 'a'; c <= 'z'; c++) {
JsonVariant *k;
const char *z;
@ -563,7 +543,7 @@ int main(int argc, char *argv[]) {
test_variant("{\"k\": \"v\", \"foo\": [1, 2, 3], \"bar\": {\"zap\": null}}", test_1);
test_variant("{\"mutant\": [1, null, \"1\", {\"1\": [1, \"1\"]}], \"thisisaverylongproperty\": 1.27}", test_2);
test_variant("{\"foo\" : \"\\u0935\\u093f\\u0935\\u0947\\u0915\\u0916\\u094d\\u092f\\u093e\\u0924\\u093f\\u0930\\u0935\\u093f\\u092a\\u094d\\u0932\\u0935\\u093e\\u0020\\u0939\\u093e\\u0928\\u094b\\u092a\\u093e\\u092f\\u0903\\u0964\"}", NULL);
test_variant("{\"foo\" : \"\\uDBFF\\uDFFF\\\"\\uD9FF\\uDFFFFFF\\\"\\uDBFF\\uDFFF\\\"\\uD9FF\\uDFFF\\uDBFF\\uDFFFF\\uDBFF\\uDFFF\\uDBFF\\uDFFF\\uDBFF\\uDFFF\\uDBFF\\uDFFF\\\"\\uD9FF\\uDFFFFF\\\"\\uDBFF\\uDFFF\\\"\\uD9FF\\uDFFF\\uDBFF\\uDFFF\"}", NULL);
test_variant("[ 0, -0, 0.0, -0.0, 0.000, -0.000, 0e0, -0e0, 0e+0, -0e-0, 0e-0, -0e000, 0e+000 ]", test_zeroes);

View File

@ -18,25 +18,6 @@ static void test_utf8_is_printable(void) {
assert_se(utf8_is_printable("\t", 1));
}
static void test_utf8_n_is_valid(void) {
log_info("/* %s */", __func__);
assert_se( utf8_is_valid_n("ascii is valid unicode", 21));
assert_se( utf8_is_valid_n("ascii is valid unicode", 22));
assert_se(!utf8_is_valid_n("ascii is valid unicode", 23));
assert_se( utf8_is_valid_n("\342\204\242", 0));
assert_se(!utf8_is_valid_n("\342\204\242", 1));
assert_se(!utf8_is_valid_n("\342\204\242", 2));
assert_se( utf8_is_valid_n("\342\204\242", 3));
assert_se(!utf8_is_valid_n("\342\204\242", 4));
assert_se( utf8_is_valid_n("<ZZ>", 0));
assert_se( utf8_is_valid_n("<ZZ>", 1));
assert_se( utf8_is_valid_n("<ZZ>", 2));
assert_se( utf8_is_valid_n("<ZZ>", 3));
assert_se( utf8_is_valid_n("<ZZ>", 4));
assert_se(!utf8_is_valid_n("<ZZ>", 5));
}
static void test_utf8_is_valid(void) {
log_info("/* %s */", __func__);
@ -235,7 +216,6 @@ static void test_utf8_to_utf16(void) {
}
int main(int argc, char *argv[]) {
test_utf8_n_is_valid();
test_utf8_is_valid();
test_utf8_is_printable();
test_ascii_is_valid();

View File

@ -8,6 +8,7 @@
#include "fd-util.h"
#include "format-table.h"
#include "format-util.h"
#include "group-record-show.h"
#include "main-func.h"
#include "pager.h"
#include "parse-util.h"
@ -686,8 +687,7 @@ static int parse_argv(int argc, char *argv[]) {
else if (streq(optarg, "help")) {
puts("classic\n"
"friendly\n"
"json\n"
"table");
"json");
return 0;
} else
return log_error_errno(SYNTHETIC_ERRNO(EINVAL), "Invalid --output= mode: %s", optarg);

View File

@ -11,7 +11,7 @@
/* This service offers two Varlink services, both implementing io.systemd.UserDatabase:
*
* io.systemd.NameServiceSwitch: this is a compatibility interface for glibc NSS: it responds to
* io.systemd.NameServiceSwitch: this is a compatibility interface for glibc NSS: it response to
* name lookups by checking the classic NSS interfaces and responding that.
*
* io.systemd.Multiplexer: this multiplexes lookup requests to all Varlink services that have a

View File

@ -7,6 +7,7 @@
#include "env-util.h"
#include "fd-util.h"
#include "group-record-nss.h"
#include "group-record.h"
#include "io-util.h"
#include "main-func.h"