Compare commits
19 Commits
e71f5585b9
...
caf6bd166f
Author | SHA1 | Date |
---|---|---|
Lennart Poettering | caf6bd166f | |
Lennart Poettering | 1b13600948 | |
Zbigniew Jędrzejewski-Szmek | 843ce053b4 | |
Lennart Poettering | b0073a017b | |
Lennart Poettering | 4d89db12fc | |
Lennart Poettering | 7baf10a7be | |
Lennart Poettering | 679badd7ba | |
Lennart Poettering | 64dc138d1e | |
Lennart Poettering | df14bda2b5 | |
Lennart Poettering | 6d7b47eb3e | |
Lennart Poettering | a2a8a509cd | |
Lennart Poettering | 5e5e11b874 | |
Zbigniew Jędrzejewski-Szmek | 3a193ac62e | |
Zbigniew Jędrzejewski-Szmek | 618727dae5 | |
Zbigniew Jędrzejewski-Szmek | 9a485918db | |
Zbigniew Jędrzejewski-Szmek | b91ae210e6 | |
Zbigniew Jędrzejewski-Szmek | a9134af2e3 | |
Zbigniew Jędrzejewski-Szmek | 01ecb3674a | |
Zbigniew Jędrzejewski-Szmek | c2cfb12641 |
21
NEWS
21
NEWS
|
@ -114,7 +114,9 @@ CHANGES WITH 246:
|
||||||
|
|
||||||
* tmpfs mounts automatically created by systemd (/tmp, /run, /dev/shm,
|
* tmpfs mounts automatically created by systemd (/tmp, /run, /dev/shm,
|
||||||
and others) now have a size and inode limits applied (50% of RAM for
|
and others) now have a size and inode limits applied (50% of RAM for
|
||||||
/tmp and /dev/shm, 10% of RAM for other mounts, etc.)
|
/tmp and /dev/shm, 10% of RAM for other mounts, etc.). Please note
|
||||||
|
that the implicit kernel default is 50% too, so there is no change
|
||||||
|
in the size limit for /tmp and /dev/shm.
|
||||||
|
|
||||||
* nss-mymachines lost support for resolution of users and groups, and
|
* nss-mymachines lost support for resolution of users and groups, and
|
||||||
now only does resolution of hostnames. This functionality is now
|
now only does resolution of hostnames. This functionality is now
|
||||||
|
@ -156,12 +158,17 @@ CHANGES WITH 246:
|
||||||
now automatically set to "Y" at boot, in order to enable pstore
|
now automatically set to "Y" at boot, in order to enable pstore
|
||||||
generation for collection with systemd-pstore.
|
generation for collection with systemd-pstore.
|
||||||
|
|
||||||
* A new 'hwdb' file has been added that collects information about PCI
|
* We provide a set of udev rules to enable auto-suspend on PCI and USB
|
||||||
and USB devices that correctly support auto-suspend, on top of the
|
devices that were tested to currectly support it. Previously, this
|
||||||
databases for this we import from the ChromiumOS project. If you have
|
was distributed as a set of udev rules, but has now been replaced by
|
||||||
a device that supports auto-suspend correctly and where it should be
|
by a set of hwdb entries (and a much shorter udev rule to take action
|
||||||
enabled by default, please submit a patch that adds it to the
|
if the device modalias matches one of the new hwdb entries).
|
||||||
database (see /usr/lib/udev/hwdb.d/60-autosuspend.hwdb).
|
|
||||||
|
As before, entries are periodically imported from the database
|
||||||
|
maintained by the ChromiumOS project. If you have a device that
|
||||||
|
supports auto-suspend correctly and where it should be enabled by
|
||||||
|
default, please submit a patch that adds it to the database (see
|
||||||
|
/usr/lib/udev/hwdb.d/60-autosuspend.hwdb).
|
||||||
|
|
||||||
* systemd-udevd gained the new configuration option timeout_signal= as well
|
* systemd-udevd gained the new configuration option timeout_signal= as well
|
||||||
as a corresponding kernel command line option udev.timeout_signal=.
|
as a corresponding kernel command line option udev.timeout_signal=.
|
||||||
|
|
4
TODO
4
TODO
|
@ -87,8 +87,7 @@ Features:
|
||||||
|
|
||||||
* make us use dynamically fewer deps for containers in general purpose distros:
|
* make us use dynamically fewer deps for containers in general purpose distros:
|
||||||
o turn into dlopen() deps:
|
o turn into dlopen() deps:
|
||||||
- libpwquality (always) - only relevant for homed, and maybe soon
|
- libidn2 (always)
|
||||||
firstboot
|
|
||||||
- elfutils (always)
|
- elfutils (always)
|
||||||
- p11-kit-trust (always)
|
- p11-kit-trust (always)
|
||||||
- kmod-libs (only when called from PID 1)
|
- kmod-libs (only when called from PID 1)
|
||||||
|
@ -365,7 +364,6 @@ Features:
|
||||||
- fingerprint authentication, pattern authentication, …
|
- fingerprint authentication, pattern authentication, …
|
||||||
- make sure "classic" user records can also be managed by homed
|
- make sure "classic" user records can also be managed by homed
|
||||||
- make size of $XDG_RUNTIME_DIR configurable in user record
|
- make size of $XDG_RUNTIME_DIR configurable in user record
|
||||||
- reuse pwquality magic in firstboot
|
|
||||||
- query password from kernel keyring first
|
- query password from kernel keyring first
|
||||||
- update even if record is "absent"
|
- update even if record is "absent"
|
||||||
- add a "access mode" + "fstype" field to the "status" section of json identity records reflecting the actually used access mode and fstype, even on non-luks backends
|
- add a "access mode" + "fstype" field to the "status" section of json identity records reflecting the actually used access mode and fstype, even on non-luks backends
|
||||||
|
|
|
@ -566,8 +566,8 @@
|
||||||
<term><option>--fs-type=</option><replaceable>TYPE</replaceable></term>
|
<term><option>--fs-type=</option><replaceable>TYPE</replaceable></term>
|
||||||
|
|
||||||
<listitem><para>When LUKS2 storage is used configures the file system type to use inside the home
|
<listitem><para>When LUKS2 storage is used configures the file system type to use inside the home
|
||||||
directory LUKS2 container. One of <literal>ext4</literal>, <literal>xfs</literal>,
|
directory LUKS2 container. One of <literal>btrfs</literal>, <literal>ext4</literal>,
|
||||||
<literal>btrfs</literal>. If not specified
|
<literal>xfs</literal>. If not specified
|
||||||
<citerefentry><refentrytitle>homed.conf</refentrytitle><manvolnum>5</manvolnum></citerefentry>
|
<citerefentry><refentrytitle>homed.conf</refentrytitle><manvolnum>5</manvolnum></citerefentry>
|
||||||
defines which default file system type to use. Note that <literal>xfs</literal> is not recommended as
|
defines which default file system type to use. Note that <literal>xfs</literal> is not recommended as
|
||||||
its support for file system resizing is too limited.</para></listitem>
|
its support for file system resizing is too limited.</para></listitem>
|
||||||
|
|
|
@ -63,9 +63,9 @@
|
||||||
<varlistentry>
|
<varlistentry>
|
||||||
<term><varname>DefaultFileSystemType=</varname></term>
|
<term><varname>DefaultFileSystemType=</varname></term>
|
||||||
<listitem><para>When using <literal>luks</literal> as storage (see above), selects the default file
|
<listitem><para>When using <literal>luks</literal> as storage (see above), selects the default file
|
||||||
system to use inside the user's LUKS volume. Takes one of <literal>ext4</literal>,
|
system to use inside the user's LUKS volume. Takes one of <literal>btrfs</literal>,
|
||||||
<literal>xfs</literal> or <literal>btrfs</literal>. If not specified defaults to
|
<literal>ext4</literal> or <literal>xfs</literal>. If not specified defaults to
|
||||||
<literal>ext4</literal>. This setting has no effect if a different storage mechanism is used. The
|
<literal>btrfs</literal>. This setting has no effect if a different storage mechanism is used. The
|
||||||
file system type selected on the <command>homectl</command> command line always takes
|
file system type selected on the <command>homectl</command> command line always takes
|
||||||
precedence.</para></listitem>
|
precedence.</para></listitem>
|
||||||
</varlistentry>
|
</varlistentry>
|
||||||
|
|
|
@ -453,7 +453,7 @@
|
||||||
<term><option>--quiet</option></term>
|
<term><option>--quiet</option></term>
|
||||||
|
|
||||||
<listitem><para>Suppresses all informational messages
|
<listitem><para>Suppresses all informational messages
|
||||||
(i.e. "-- Logs begin at …", "-- Reboot --"),
|
(i.e. "-- Journal begins at …", "-- Reboot --"),
|
||||||
any warning messages regarding
|
any warning messages regarding
|
||||||
inaccessible system journals when run as a normal
|
inaccessible system journals when run as a normal
|
||||||
user.</para></listitem>
|
user.</para></listitem>
|
||||||
|
|
|
@ -463,11 +463,11 @@ Mon Dec 8 20:44:24 KST 2014
|
||||||
Running as unit: run-71.timer
|
Running as unit: run-71.timer
|
||||||
Will run service as unit: run-71.service
|
Will run service as unit: run-71.service
|
||||||
# journalctl -b -u run-71.timer
|
# journalctl -b -u run-71.timer
|
||||||
-- Logs begin at Fri 2014-12-05 19:09:21 KST, end at Mon 2014-12-08 20:44:54 KST. --
|
-- Journal begins at Fri 2014-12-05 19:09:21 KST, ends at Mon 2014-12-08 20:44:54 KST. --
|
||||||
Dec 08 20:44:38 container systemd[1]: Starting /bin/touch /tmp/foo.
|
Dec 08 20:44:38 container systemd[1]: Starting /bin/touch /tmp/foo.
|
||||||
Dec 08 20:44:38 container systemd[1]: Started /bin/touch /tmp/foo.
|
Dec 08 20:44:38 container systemd[1]: Started /bin/touch /tmp/foo.
|
||||||
# journalctl -b -u run-71.service
|
# journalctl -b -u run-71.service
|
||||||
-- Logs begin at Fri 2014-12-05 19:09:21 KST, end at Mon 2014-12-08 20:44:54 KST. --
|
-- Journal begins at Fri 2014-12-05 19:09:21 KST, ends at Mon 2014-12-08 20:44:54 KST. --
|
||||||
Dec 08 20:44:48 container systemd[1]: Starting /bin/touch /tmp/foo...
|
Dec 08 20:44:48 container systemd[1]: Starting /bin/touch /tmp/foo...
|
||||||
Dec 08 20:44:48 container systemd[1]: Started /bin/touch /tmp/foo.</programlisting>
|
Dec 08 20:44:48 container systemd[1]: Started /bin/touch /tmp/foo.</programlisting>
|
||||||
</example>
|
</example>
|
||||||
|
|
|
@ -2174,8 +2174,7 @@ if conf.get('ENABLE_HOMED') == 1
|
||||||
link_with : [libshared],
|
link_with : [libshared],
|
||||||
dependencies : [threads,
|
dependencies : [threads,
|
||||||
libcrypt,
|
libcrypt,
|
||||||
libopenssl,
|
libopenssl],
|
||||||
libpwquality],
|
|
||||||
install_rpath : rootlibexecdir,
|
install_rpath : rootlibexecdir,
|
||||||
install : true,
|
install : true,
|
||||||
install_dir : rootlibexecdir)
|
install_dir : rootlibexecdir)
|
||||||
|
@ -2189,8 +2188,7 @@ if conf.get('ENABLE_HOMED') == 1
|
||||||
libcrypt,
|
libcrypt,
|
||||||
libopenssl,
|
libopenssl,
|
||||||
libp11kit,
|
libp11kit,
|
||||||
libfido2,
|
libfido2],
|
||||||
libpwquality],
|
|
||||||
install_rpath : rootlibexecdir,
|
install_rpath : rootlibexecdir,
|
||||||
install : true,
|
install : true,
|
||||||
install_dir : rootbindir)
|
install_dir : rootbindir)
|
||||||
|
|
|
@ -139,7 +139,7 @@ _homectl() {
|
||||||
comps=$(cat /etc/shells)
|
comps=$(cat /etc/shells)
|
||||||
;;
|
;;
|
||||||
--fs-type)
|
--fs-type)
|
||||||
comps='ext4 xfs btrsf'
|
comps='btrfs ext4 xfs'
|
||||||
;;
|
;;
|
||||||
--cifs-user-name)
|
--cifs-user-name)
|
||||||
comps=$(compgen -A user -- "$cur" )
|
comps=$(compgen -A user -- "$cur" )
|
||||||
|
|
|
@ -493,7 +493,7 @@ static int assess_system_call_architectures(
|
||||||
|
|
||||||
#if HAVE_SECCOMP
|
#if HAVE_SECCOMP
|
||||||
|
|
||||||
static bool syscall_names_in_filter(Set *s, bool allow_list, const SyscallFilterSet *f) {
|
static bool syscall_names_in_filter(Set *s, bool allow_list, const SyscallFilterSet *f, const char **ret_offending_syscall) {
|
||||||
const char *syscall;
|
const char *syscall;
|
||||||
|
|
||||||
NULSTR_FOREACH(syscall, f->value) {
|
NULSTR_FOREACH(syscall, f->value) {
|
||||||
|
@ -503,7 +503,7 @@ static bool syscall_names_in_filter(Set *s, bool allow_list, const SyscallFilter
|
||||||
const SyscallFilterSet *g;
|
const SyscallFilterSet *g;
|
||||||
|
|
||||||
assert_se(g = syscall_filter_set_find(syscall));
|
assert_se(g = syscall_filter_set_find(syscall));
|
||||||
if (syscall_names_in_filter(s, allow_list, g))
|
if (syscall_names_in_filter(s, allow_list, g, ret_offending_syscall))
|
||||||
return true; /* bad! */
|
return true; /* bad! */
|
||||||
|
|
||||||
continue;
|
continue;
|
||||||
|
@ -516,10 +516,13 @@ static bool syscall_names_in_filter(Set *s, bool allow_list, const SyscallFilter
|
||||||
|
|
||||||
if (set_contains(s, syscall) == allow_list) {
|
if (set_contains(s, syscall) == allow_list) {
|
||||||
log_debug("Offending syscall filter item: %s", syscall);
|
log_debug("Offending syscall filter item: %s", syscall);
|
||||||
|
if (ret_offending_syscall)
|
||||||
|
*ret_offending_syscall = syscall;
|
||||||
return true; /* bad! */
|
return true; /* bad! */
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
*ret_offending_syscall = NULL;
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -530,43 +533,49 @@ static int assess_system_call_filter(
|
||||||
uint64_t *ret_badness,
|
uint64_t *ret_badness,
|
||||||
char **ret_description) {
|
char **ret_description) {
|
||||||
|
|
||||||
const SyscallFilterSet *f;
|
|
||||||
char *d = NULL;
|
|
||||||
uint64_t b;
|
|
||||||
|
|
||||||
assert(a);
|
assert(a);
|
||||||
assert(info);
|
assert(info);
|
||||||
assert(ret_badness);
|
assert(ret_badness);
|
||||||
assert(ret_description);
|
assert(ret_description);
|
||||||
|
|
||||||
assert(a->parameter < _SYSCALL_FILTER_SET_MAX);
|
assert(a->parameter < _SYSCALL_FILTER_SET_MAX);
|
||||||
f = syscall_filter_sets + a->parameter;
|
const SyscallFilterSet *f = syscall_filter_sets + a->parameter;
|
||||||
|
|
||||||
|
char *d = NULL;
|
||||||
|
uint64_t b;
|
||||||
|
|
||||||
if (!info->system_call_filter_allow_list && set_isempty(info->system_call_filter)) {
|
if (!info->system_call_filter_allow_list && set_isempty(info->system_call_filter)) {
|
||||||
d = strdup("Service does not filter system calls");
|
d = strdup("Service does not filter system calls");
|
||||||
b = 10;
|
b = 10;
|
||||||
} else {
|
} else {
|
||||||
bool bad;
|
bool bad;
|
||||||
|
const char *offender = NULL;
|
||||||
|
|
||||||
log_debug("Analyzing system call filter, checking against: %s", f->name);
|
log_debug("Analyzing system call filter, checking against: %s", f->name);
|
||||||
bad = syscall_names_in_filter(info->system_call_filter, info->system_call_filter_allow_list, f);
|
bad = syscall_names_in_filter(info->system_call_filter, info->system_call_filter_allow_list, f, &offender);
|
||||||
log_debug("Result: %s", bad ? "bad" : "good");
|
log_debug("Result: %s", bad ? "bad" : "good");
|
||||||
|
|
||||||
if (info->system_call_filter_allow_list) {
|
if (info->system_call_filter_allow_list) {
|
||||||
if (bad) {
|
if (bad) {
|
||||||
(void) asprintf(&d, "System call allow list defined for service, and %s is included", f->name);
|
(void) asprintf(&d, "System call allow list defined for service, and %s is included "
|
||||||
|
"(e.g. %s is allowed)",
|
||||||
|
f->name, offender);
|
||||||
b = 9;
|
b = 9;
|
||||||
} else {
|
} else {
|
||||||
(void) asprintf(&d, "System call allow list defined for service, and %s is not included", f->name);
|
(void) asprintf(&d, "System call allow list defined for service, and %s is not included",
|
||||||
|
f->name);
|
||||||
b = 0;
|
b = 0;
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
if (bad) {
|
if (bad) {
|
||||||
(void) asprintf(&d, "System call deny list defined for service, and %s is not included", f->name);
|
(void) asprintf(&d, "System call deny list defined for service, and %s is not included "
|
||||||
|
"(e.g. %s is allowed)",
|
||||||
|
f->name, offender);
|
||||||
b = 10;
|
b = 10;
|
||||||
} else {
|
} else {
|
||||||
(void) asprintf(&d, "System call deny list defined for service, and %s is included", f->name);
|
(void) asprintf(&d, "System call deny list defined for service, and %s is included",
|
||||||
b = 5;
|
f->name);
|
||||||
|
b = 0;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -135,8 +135,8 @@ char *strjoin_real(const char *x, ...) _sentinel_;
|
||||||
({ \
|
({ \
|
||||||
const char *_appendees_[] = { a, __VA_ARGS__ }; \
|
const char *_appendees_[] = { a, __VA_ARGS__ }; \
|
||||||
char *_d_, *_p_; \
|
char *_d_, *_p_; \
|
||||||
size_t _len_ = 0; \
|
size_t _len_ = 0; \
|
||||||
size_t _i_; \
|
size_t _i_; \
|
||||||
for (_i_ = 0; _i_ < ELEMENTSOF(_appendees_) && _appendees_[_i_]; _i_++) \
|
for (_i_ = 0; _i_ < ELEMENTSOF(_appendees_) && _appendees_[_i_]; _i_++) \
|
||||||
_len_ += strlen(_appendees_[_i_]); \
|
_len_ += strlen(_appendees_[_i_]); \
|
||||||
_p_ = _d_ = newa(char, _len_ + 1); \
|
_p_ = _d_ = newa(char, _len_ + 1); \
|
||||||
|
@ -152,7 +152,6 @@ char *delete_trailing_chars(char *s, const char *bad);
|
||||||
char *truncate_nl(char *s);
|
char *truncate_nl(char *s);
|
||||||
|
|
||||||
static inline char *skip_leading_chars(const char *s, const char *bad) {
|
static inline char *skip_leading_chars(const char *s, const char *bad) {
|
||||||
|
|
||||||
if (!s)
|
if (!s)
|
||||||
return NULL;
|
return NULL;
|
||||||
|
|
||||||
|
@ -231,11 +230,9 @@ REENABLE_WARNING;
|
||||||
|
|
||||||
/* Like startswith(), but operates on arbitrary memory blocks */
|
/* Like startswith(), but operates on arbitrary memory blocks */
|
||||||
static inline void *memory_startswith(const void *p, size_t sz, const char *token) {
|
static inline void *memory_startswith(const void *p, size_t sz, const char *token) {
|
||||||
size_t n;
|
|
||||||
|
|
||||||
assert(token);
|
assert(token);
|
||||||
|
|
||||||
n = strlen(token);
|
size_t n = strlen(token);
|
||||||
if (sz < n)
|
if (sz < n)
|
||||||
return NULL;
|
return NULL;
|
||||||
|
|
||||||
|
@ -251,20 +248,17 @@ static inline void *memory_startswith(const void *p, size_t sz, const char *toke
|
||||||
* It works only for ASCII strings.
|
* It works only for ASCII strings.
|
||||||
*/
|
*/
|
||||||
static inline void *memory_startswith_no_case(const void *p, size_t sz, const char *token) {
|
static inline void *memory_startswith_no_case(const void *p, size_t sz, const char *token) {
|
||||||
size_t n, i;
|
|
||||||
|
|
||||||
assert(token);
|
assert(token);
|
||||||
|
|
||||||
n = strlen(token);
|
size_t n = strlen(token);
|
||||||
if (sz < n)
|
if (sz < n)
|
||||||
return NULL;
|
return NULL;
|
||||||
|
|
||||||
assert(p);
|
assert(p);
|
||||||
|
|
||||||
for (i = 0; i < n; i++) {
|
for (size_t i = 0; i < n; i++)
|
||||||
if (ascii_tolower(((char *)p)[i]) != ascii_tolower(token[i]))
|
if (ascii_tolower(((char *)p)[i]) != ascii_tolower(token[i]))
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
|
||||||
|
|
||||||
return (uint8_t*) p + n;
|
return (uint8_t*) p + n;
|
||||||
}
|
}
|
||||||
|
|
|
@ -123,7 +123,7 @@ int utf8_encoded_to_unichar(const char *str, char32_t *ret_unichar) {
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool utf8_is_printable_newline(const char* str, size_t length, bool newline) {
|
bool utf8_is_printable_newline(const char* str, size_t length, bool allow_newline) {
|
||||||
const char *p;
|
const char *p;
|
||||||
|
|
||||||
assert(str);
|
assert(str);
|
||||||
|
@ -140,7 +140,7 @@ bool utf8_is_printable_newline(const char* str, size_t length, bool newline) {
|
||||||
r = utf8_encoded_to_unichar(p, &val);
|
r = utf8_encoded_to_unichar(p, &val);
|
||||||
if (r < 0 ||
|
if (r < 0 ||
|
||||||
unichar_is_control(val) ||
|
unichar_is_control(val) ||
|
||||||
(!newline && val == '\n'))
|
(!allow_newline && val == '\n'))
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
length -= encoded_len;
|
length -= encoded_len;
|
||||||
|
|
|
@ -18,7 +18,7 @@ char *utf8_is_valid(const char *s) _pure_;
|
||||||
char *ascii_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);
|
char *ascii_is_valid_n(const char *str, size_t len);
|
||||||
|
|
||||||
bool utf8_is_printable_newline(const char* str, size_t length, bool newline) _pure_;
|
bool utf8_is_printable_newline(const char* str, size_t length, bool allow_newline) _pure_;
|
||||||
#define utf8_is_printable(str, length) utf8_is_printable_newline(str, length, true)
|
#define utf8_is_printable(str, length) utf8_is_printable_newline(str, length, true)
|
||||||
|
|
||||||
char *utf8_escape_invalid(const char *s);
|
char *utf8_escape_invalid(const char *s);
|
||||||
|
|
|
@ -28,6 +28,7 @@
|
||||||
#include "path-util.h"
|
#include "path-util.h"
|
||||||
#include "pretty-print.h"
|
#include "pretty-print.h"
|
||||||
#include "proc-cmdline.h"
|
#include "proc-cmdline.h"
|
||||||
|
#include "pwquality-util.h"
|
||||||
#include "random-util.h"
|
#include "random-util.h"
|
||||||
#include "string-util.h"
|
#include "string-util.h"
|
||||||
#include "strv.h"
|
#include "strv.h"
|
||||||
|
@ -568,8 +569,11 @@ static int prompt_root_password(void) {
|
||||||
msg1 = strjoina(special_glyph(SPECIAL_GLYPH_TRIANGULAR_BULLET), " Please enter a new root password (empty to skip):");
|
msg1 = strjoina(special_glyph(SPECIAL_GLYPH_TRIANGULAR_BULLET), " Please enter a new root password (empty to skip):");
|
||||||
msg2 = strjoina(special_glyph(SPECIAL_GLYPH_TRIANGULAR_BULLET), " Please enter new root password again:");
|
msg2 = strjoina(special_glyph(SPECIAL_GLYPH_TRIANGULAR_BULLET), " Please enter new root password again:");
|
||||||
|
|
||||||
|
suggest_passwords();
|
||||||
|
|
||||||
for (;;) {
|
for (;;) {
|
||||||
_cleanup_strv_free_erase_ char **a = NULL, **b = NULL;
|
_cleanup_strv_free_erase_ char **a = NULL, **b = NULL;
|
||||||
|
_cleanup_free_ char *error = NULL;
|
||||||
|
|
||||||
r = ask_password_tty(-1, msg1, NULL, 0, 0, NULL, &a);
|
r = ask_password_tty(-1, msg1, NULL, 0, 0, NULL, &a);
|
||||||
if (r < 0)
|
if (r < 0)
|
||||||
|
@ -583,6 +587,12 @@ static int prompt_root_password(void) {
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
r = quality_check_password(*a, "root", &error);
|
||||||
|
if (r < 0)
|
||||||
|
return log_error_errno(r, "Failed to check quality of password: %m");
|
||||||
|
if (r == 0)
|
||||||
|
log_warning("Password is weak, accepting anyway: %s", error);
|
||||||
|
|
||||||
r = ask_password_tty(-1, msg2, NULL, 0, 0, NULL, &b);
|
r = ask_password_tty(-1, msg2, NULL, 0, 0, NULL, &b);
|
||||||
if (r < 0)
|
if (r < 0)
|
||||||
return log_error_errno(r, "Failed to query root password: %m");
|
return log_error_errno(r, "Failed to query root password: %m");
|
||||||
|
|
|
@ -30,6 +30,7 @@
|
||||||
#include "rlimit-util.h"
|
#include "rlimit-util.h"
|
||||||
#include "spawn-polkit-agent.h"
|
#include "spawn-polkit-agent.h"
|
||||||
#include "terminal-util.h"
|
#include "terminal-util.h"
|
||||||
|
#include "user-record-pwquality.h"
|
||||||
#include "user-record-show.h"
|
#include "user-record-show.h"
|
||||||
#include "user-record-util.h"
|
#include "user-record-util.h"
|
||||||
#include "user-record.h"
|
#include "user-record.h"
|
||||||
|
@ -1097,7 +1098,7 @@ static int create_home(int argc, char *argv[], void *userdata) {
|
||||||
|
|
||||||
/* If password quality enforcement is disabled, let's at least warn client side */
|
/* If password quality enforcement is disabled, let's at least warn client side */
|
||||||
|
|
||||||
r = quality_check_password(hr, hr, &error);
|
r = user_record_quality_check_password(hr, hr, &error);
|
||||||
if (r < 0)
|
if (r < 0)
|
||||||
log_warning_errno(r, "Specified password does not pass quality checks (%s), proceeding anyway.", bus_error_message(&error, r));
|
log_warning_errno(r, "Specified password does not pass quality checks (%s), proceeding anyway.", bus_error_message(&error, r));
|
||||||
}
|
}
|
||||||
|
@ -1955,7 +1956,7 @@ static int help(int argc, char *argv[], void *userdata) {
|
||||||
" --image-path=PATH Path to image file/directory\n"
|
" --image-path=PATH Path to image file/directory\n"
|
||||||
"\n%4$sLUKS Storage User Record Properties:%5$s\n"
|
"\n%4$sLUKS Storage User Record Properties:%5$s\n"
|
||||||
" --fs-type=TYPE File system type to use in case of luks\n"
|
" --fs-type=TYPE File system type to use in case of luks\n"
|
||||||
" storage (ext4, xfs, btrfs)\n"
|
" storage (btrfs, ext4, xfs)\n"
|
||||||
" --luks-discard=BOOL Whether to use 'discard' feature of file system\n"
|
" --luks-discard=BOOL Whether to use 'discard' feature of file system\n"
|
||||||
" when activated (mounted)\n"
|
" when activated (mounted)\n"
|
||||||
" --luks-offline-discard=BOOL\n"
|
" --luks-offline-discard=BOOL\n"
|
||||||
|
|
|
@ -33,6 +33,7 @@
|
||||||
#include "strv.h"
|
#include "strv.h"
|
||||||
#include "user-record-sign.h"
|
#include "user-record-sign.h"
|
||||||
#include "user-record-util.h"
|
#include "user-record-util.h"
|
||||||
|
#include "user-record-pwquality.h"
|
||||||
#include "user-record.h"
|
#include "user-record.h"
|
||||||
#include "user-util.h"
|
#include "user-util.h"
|
||||||
|
|
||||||
|
@ -1289,7 +1290,7 @@ int home_create(Home *h, UserRecord *secret, sd_bus_error *error) {
|
||||||
if (h->record->enforce_password_policy == false)
|
if (h->record->enforce_password_policy == false)
|
||||||
log_debug("Password quality check turned off for account, skipping.");
|
log_debug("Password quality check turned off for account, skipping.");
|
||||||
else {
|
else {
|
||||||
r = quality_check_password(h->record, secret, error);
|
r = user_record_quality_check_password(h->record, secret, error);
|
||||||
if (r < 0)
|
if (r < 0)
|
||||||
return r;
|
return r;
|
||||||
}
|
}
|
||||||
|
@ -1640,7 +1641,7 @@ int home_passwd(Home *h,
|
||||||
if (c->enforce_password_policy == false)
|
if (c->enforce_password_policy == false)
|
||||||
log_debug("Password quality check turned off for account, skipping.");
|
log_debug("Password quality check turned off for account, skipping.");
|
||||||
else {
|
else {
|
||||||
r = quality_check_password(c, merged_secret, error);
|
r = user_record_quality_check_password(c, merged_secret, error);
|
||||||
if (r < 0)
|
if (r < 0)
|
||||||
return r;
|
return r;
|
||||||
}
|
}
|
||||||
|
|
|
@ -512,6 +512,8 @@ static int search_quota(uid_t uid, const char *exclude_quota_path) {
|
||||||
if (r < 0) {
|
if (r < 0) {
|
||||||
if (ERRNO_IS_NOT_SUPPORTED(r))
|
if (ERRNO_IS_NOT_SUPPORTED(r))
|
||||||
log_debug_errno(r, "No UID quota support on %s, ignoring.", where);
|
log_debug_errno(r, "No UID quota support on %s, ignoring.", where);
|
||||||
|
else if (ERRNO_IS_PRIVILEGE(r))
|
||||||
|
log_debug_errno(r, "UID quota support for %s prohibited, ignoring.", where);
|
||||||
else
|
else
|
||||||
log_warning_errno(r, "Failed to query quota on %s, ignoring: %m", where);
|
log_warning_errno(r, "Failed to query quota on %s, ignoring: %m", where);
|
||||||
|
|
||||||
|
|
|
@ -13,4 +13,4 @@
|
||||||
|
|
||||||
[Home]
|
[Home]
|
||||||
#DefaultStorage=
|
#DefaultStorage=
|
||||||
#DefaultFileSystemType=ext4
|
#DefaultFileSystemType=btrfs
|
||||||
|
|
|
@ -1110,7 +1110,9 @@ int home_prepare_luks(
|
||||||
if (fstat(fd, &st) < 0)
|
if (fstat(fd, &st) < 0)
|
||||||
return log_error_errno(errno, "Failed to fstat() image file: %m");
|
return log_error_errno(errno, "Failed to fstat() image file: %m");
|
||||||
if (!S_ISREG(st.st_mode) && !S_ISBLK(st.st_mode))
|
if (!S_ISREG(st.st_mode) && !S_ISBLK(st.st_mode))
|
||||||
return log_error_errno(errno, "Image file %s is not a regular file or block device: %m", ip);
|
return log_error_errno(
|
||||||
|
S_ISDIR(st.st_mode) ? SYNTHETIC_ERRNO(EISDIR) : SYNTHETIC_ERRNO(EBADFD),
|
||||||
|
"Image file %s is not a regular file or block device: %m", ip);
|
||||||
|
|
||||||
r = luks_validate(fd, user_record_user_name_and_realm(h), h->partition_uuid, &found_partition_uuid, &offset, &size);
|
r = luks_validate(fd, user_record_user_name_and_realm(h), h->partition_uuid, &found_partition_uuid, &offset, &size);
|
||||||
if (r < 0)
|
if (r < 0)
|
||||||
|
@ -2015,7 +2017,8 @@ int home_create_luks(
|
||||||
|
|
||||||
r = chattr_fd(image_fd, FS_NOCOW_FL, FS_NOCOW_FL, NULL);
|
r = chattr_fd(image_fd, FS_NOCOW_FL, FS_NOCOW_FL, NULL);
|
||||||
if (r < 0)
|
if (r < 0)
|
||||||
log_warning_errno(r, "Failed to set file attributes on %s, ignoring: %m", temporary_image_path);
|
log_full_errno(ERRNO_IS_NOT_SUPPORTED(r) ? LOG_DEBUG : LOG_WARNING, r,
|
||||||
|
"Failed to set file attributes on %s, ignoring: %m", temporary_image_path);
|
||||||
|
|
||||||
r = home_truncate(h, image_fd, temporary_image_path, host_size);
|
r = home_truncate(h, image_fd, temporary_image_path, host_size);
|
||||||
if (r < 0)
|
if (r < 0)
|
||||||
|
@ -2164,6 +2167,9 @@ int home_create_luks(
|
||||||
goto fail;
|
goto fail;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
crypt_free(cd);
|
||||||
|
cd = NULL;
|
||||||
|
|
||||||
dm_activated = false;
|
dm_activated = false;
|
||||||
|
|
||||||
loop = loop_device_unref(loop);
|
loop = loop_device_unref(loop);
|
||||||
|
@ -2174,8 +2180,22 @@ int home_create_luks(
|
||||||
goto fail;
|
goto fail;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Sync everything to disk before we move things into place under the final name. */
|
||||||
|
if (fsync(image_fd) < 0) {
|
||||||
|
r = log_error_errno(r, "Failed to synchronize image to disk: %m");
|
||||||
|
goto fail;
|
||||||
|
}
|
||||||
|
|
||||||
if (disk_uuid_path)
|
if (disk_uuid_path)
|
||||||
(void) ioctl(image_fd, BLKRRPART, 0);
|
(void) ioctl(image_fd, BLKRRPART, 0);
|
||||||
|
else {
|
||||||
|
/* If we operate on a file, sync the contaning directory too. */
|
||||||
|
r = fsync_directory_of_file(image_fd);
|
||||||
|
if (r < 0) {
|
||||||
|
log_error_errno(r, "Failed to synchronize directory of image file to disk: %m");
|
||||||
|
goto fail;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/* Let's close the image fd now. If we are operating on a real block device this will release the BSD
|
/* Let's close the image fd now. If we are operating on a real block device this will release the BSD
|
||||||
* lock that ensures udev doesn't interfere with what we are doing */
|
* lock that ensures udev doesn't interfere with what we are doing */
|
||||||
|
|
|
@ -50,8 +50,8 @@ systemd_homed_sources = files('''
|
||||||
homed-varlink.c
|
homed-varlink.c
|
||||||
homed-varlink.h
|
homed-varlink.h
|
||||||
homed.c
|
homed.c
|
||||||
pwquality-util.c
|
user-record-pwquality.c
|
||||||
pwquality-util.h
|
user-record-pwquality.h
|
||||||
user-record-sign.c
|
user-record-sign.c
|
||||||
user-record-sign.h
|
user-record-sign.h
|
||||||
user-record-util.c
|
user-record-util.c
|
||||||
|
@ -74,8 +74,8 @@ homectl_sources = files('''
|
||||||
homectl-pkcs11.c
|
homectl-pkcs11.c
|
||||||
homectl-pkcs11.h
|
homectl-pkcs11.h
|
||||||
homectl.c
|
homectl.c
|
||||||
pwquality-util.c
|
user-record-pwquality.c
|
||||||
pwquality-util.h
|
user-record-pwquality.h
|
||||||
user-record-util.c
|
user-record-util.c
|
||||||
user-record-util.h
|
user-record-util.h
|
||||||
'''.split())
|
'''.split())
|
||||||
|
|
|
@ -1,186 +0,0 @@
|
||||||
/* SPDX-License-Identifier: LGPL-2.1+ */
|
|
||||||
|
|
||||||
#include <unistd.h>
|
|
||||||
|
|
||||||
#if HAVE_PWQUALITY
|
|
||||||
/* pwquality.h uses size_t but doesn't include sys/types.h on its own */
|
|
||||||
#include <sys/types.h>
|
|
||||||
#include <pwquality.h>
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#include "bus-common-errors.h"
|
|
||||||
#include "home-util.h"
|
|
||||||
#include "memory-util.h"
|
|
||||||
#include "pwquality-util.h"
|
|
||||||
#include "strv.h"
|
|
||||||
|
|
||||||
#if HAVE_PWQUALITY
|
|
||||||
DEFINE_TRIVIAL_CLEANUP_FUNC(pwquality_settings_t*, pwquality_free_settings);
|
|
||||||
|
|
||||||
static void pwquality_maybe_disable_dictionary(
|
|
||||||
pwquality_settings_t *pwq) {
|
|
||||||
|
|
||||||
char buf[PWQ_MAX_ERROR_MESSAGE_LEN];
|
|
||||||
const char *path;
|
|
||||||
int r;
|
|
||||||
|
|
||||||
r = pwquality_get_str_value(pwq, PWQ_SETTING_DICT_PATH, &path);
|
|
||||||
if (r < 0) {
|
|
||||||
log_warning("Failed to read libpwquality dictionary path, ignoring: %s", pwquality_strerror(buf, sizeof(buf), r, NULL));
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
// REMOVE THIS AS SOON AS https://github.com/libpwquality/libpwquality/pull/21 IS MERGED AND RELEASED
|
|
||||||
if (isempty(path))
|
|
||||||
path = "/usr/share/cracklib/pw_dict.pwd.gz";
|
|
||||||
|
|
||||||
if (isempty(path)) {
|
|
||||||
log_warning("Weird, no dictionary file configured, ignoring.");
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (access(path, F_OK) >= 0)
|
|
||||||
return;
|
|
||||||
|
|
||||||
if (errno != ENOENT) {
|
|
||||||
log_warning_errno(errno, "Failed to check if dictionary file %s exists, ignoring: %m", path);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
r = pwquality_set_int_value(pwq, PWQ_SETTING_DICT_CHECK, 0);
|
|
||||||
if (r < 0) {
|
|
||||||
log_warning("Failed to disable libpwquality dictionary check, ignoring: %s", pwquality_strerror(buf, sizeof(buf), r, NULL));
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
int quality_check_password(
|
|
||||||
UserRecord *hr,
|
|
||||||
UserRecord *secret,
|
|
||||||
sd_bus_error *error) {
|
|
||||||
|
|
||||||
_cleanup_(pwquality_free_settingsp) pwquality_settings_t *pwq = NULL;
|
|
||||||
char buf[PWQ_MAX_ERROR_MESSAGE_LEN], **pp;
|
|
||||||
void *auxerror;
|
|
||||||
int r;
|
|
||||||
|
|
||||||
assert(hr);
|
|
||||||
assert(secret);
|
|
||||||
|
|
||||||
pwq = pwquality_default_settings();
|
|
||||||
if (!pwq)
|
|
||||||
return log_oom();
|
|
||||||
|
|
||||||
r = pwquality_read_config(pwq, NULL, &auxerror);
|
|
||||||
if (r < 0)
|
|
||||||
log_warning_errno(SYNTHETIC_ERRNO(EINVAL), "Failed to read libpwquality configuration, ignoring: %s",
|
|
||||||
pwquality_strerror(buf, sizeof(buf), r, auxerror));
|
|
||||||
|
|
||||||
pwquality_maybe_disable_dictionary(pwq);
|
|
||||||
|
|
||||||
/* This is a bit more complex than one might think at first. pwquality_check() would like to know the
|
|
||||||
* old password to make security checks. We support arbitrary numbers of passwords however, hence we
|
|
||||||
* call the function once for each combination of old and new password. */
|
|
||||||
|
|
||||||
/* Iterate through all new passwords */
|
|
||||||
STRV_FOREACH(pp, secret->password) {
|
|
||||||
bool called = false;
|
|
||||||
char **old;
|
|
||||||
|
|
||||||
r = test_password_many(hr->hashed_password, *pp);
|
|
||||||
if (r < 0)
|
|
||||||
return r;
|
|
||||||
if (r == 0) /* This is an old password as it isn't listed in the hashedPassword field, skip it */
|
|
||||||
continue;
|
|
||||||
|
|
||||||
/* Check this password against all old passwords */
|
|
||||||
STRV_FOREACH(old, secret->password) {
|
|
||||||
|
|
||||||
if (streq(*pp, *old))
|
|
||||||
continue;
|
|
||||||
|
|
||||||
r = test_password_many(hr->hashed_password, *old);
|
|
||||||
if (r < 0)
|
|
||||||
return r;
|
|
||||||
if (r > 0) /* This is a new password, not suitable as old password */
|
|
||||||
continue;
|
|
||||||
|
|
||||||
r = pwquality_check(pwq, *pp, *old, hr->user_name, &auxerror);
|
|
||||||
if (r < 0)
|
|
||||||
return sd_bus_error_setf(error, BUS_ERROR_LOW_PASSWORD_QUALITY, "Password too weak: %s",
|
|
||||||
pwquality_strerror(buf, sizeof(buf), r, auxerror));
|
|
||||||
|
|
||||||
called = true;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (called)
|
|
||||||
continue;
|
|
||||||
|
|
||||||
/* If there are no old passwords, let's call pwquality_check() without any. */
|
|
||||||
r = pwquality_check(pwq, *pp, NULL, hr->user_name, &auxerror);
|
|
||||||
if (r < 0)
|
|
||||||
return sd_bus_error_setf(error, BUS_ERROR_LOW_PASSWORD_QUALITY, "Password too weak: %s",
|
|
||||||
pwquality_strerror(buf, sizeof(buf), r, auxerror));
|
|
||||||
}
|
|
||||||
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
#define N_SUGGESTIONS 6
|
|
||||||
|
|
||||||
int suggest_passwords(void) {
|
|
||||||
_cleanup_(pwquality_free_settingsp) pwquality_settings_t *pwq = NULL;
|
|
||||||
_cleanup_strv_free_erase_ char **suggestions = NULL;
|
|
||||||
_cleanup_(erase_and_freep) char *joined = NULL;
|
|
||||||
char buf[PWQ_MAX_ERROR_MESSAGE_LEN];
|
|
||||||
void *auxerror;
|
|
||||||
size_t i;
|
|
||||||
int r;
|
|
||||||
|
|
||||||
pwq = pwquality_default_settings();
|
|
||||||
if (!pwq)
|
|
||||||
return log_oom();
|
|
||||||
|
|
||||||
r = pwquality_read_config(pwq, NULL, &auxerror);
|
|
||||||
if (r < 0)
|
|
||||||
log_warning_errno(SYNTHETIC_ERRNO(EINVAL), "Failed to read libpwquality configuration, ignoring: %s",
|
|
||||||
pwquality_strerror(buf, sizeof(buf), r, auxerror));
|
|
||||||
|
|
||||||
pwquality_maybe_disable_dictionary(pwq);
|
|
||||||
|
|
||||||
suggestions = new0(char*, N_SUGGESTIONS+1);
|
|
||||||
if (!suggestions)
|
|
||||||
return log_oom();
|
|
||||||
|
|
||||||
for (i = 0; i < N_SUGGESTIONS; i++) {
|
|
||||||
r = pwquality_generate(pwq, 64, suggestions + i);
|
|
||||||
if (r < 0)
|
|
||||||
return log_error_errno(SYNTHETIC_ERRNO(EIO), "Failed to generate password, ignoring: %s",
|
|
||||||
pwquality_strerror(buf, sizeof(buf), r, NULL));
|
|
||||||
}
|
|
||||||
|
|
||||||
joined = strv_join(suggestions, " ");
|
|
||||||
if (!joined)
|
|
||||||
return log_oom();
|
|
||||||
|
|
||||||
log_info("Password suggestions: %s", joined);
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
#else
|
|
||||||
|
|
||||||
int quality_check_password(
|
|
||||||
UserRecord *hr,
|
|
||||||
UserRecord *secret,
|
|
||||||
sd_bus_error *error) {
|
|
||||||
|
|
||||||
assert(hr);
|
|
||||||
assert(secret);
|
|
||||||
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
int suggest_passwords(void) {
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
#endif
|
|
|
@ -1,9 +0,0 @@
|
||||||
/* SPDX-License-Identifier: LGPL-2.1+ */
|
|
||||||
#pragma once
|
|
||||||
|
|
||||||
#include "sd-bus.h"
|
|
||||||
#include "user-record.h"
|
|
||||||
|
|
||||||
int quality_check_password(UserRecord *hr, UserRecord *secret, sd_bus_error *error);
|
|
||||||
|
|
||||||
int suggest_passwords(void);
|
|
|
@ -0,0 +1,90 @@
|
||||||
|
/* SPDX-License-Identifier: LGPL-2.1+ */
|
||||||
|
|
||||||
|
#include "bus-common-errors.h"
|
||||||
|
#include "errno-util.h"
|
||||||
|
#include "home-util.h"
|
||||||
|
#include "pwquality-util.h"
|
||||||
|
#include "strv.h"
|
||||||
|
#include "user-record-pwquality.h"
|
||||||
|
#include "user-record-util.h"
|
||||||
|
|
||||||
|
#if HAVE_PWQUALITY
|
||||||
|
|
||||||
|
int user_record_quality_check_password(
|
||||||
|
UserRecord *hr,
|
||||||
|
UserRecord *secret,
|
||||||
|
sd_bus_error *error) {
|
||||||
|
|
||||||
|
_cleanup_(sym_pwquality_free_settingsp) pwquality_settings_t *pwq = NULL;
|
||||||
|
char buf[PWQ_MAX_ERROR_MESSAGE_LEN], **pp;
|
||||||
|
void *auxerror;
|
||||||
|
int r;
|
||||||
|
|
||||||
|
assert(hr);
|
||||||
|
assert(secret);
|
||||||
|
|
||||||
|
r = pwq_allocate_context(&pwq);
|
||||||
|
if (ERRNO_IS_NOT_SUPPORTED(r))
|
||||||
|
return 0;
|
||||||
|
if (r < 0)
|
||||||
|
return log_debug_errno(r, "Failed to allocate libpwquality context: %m");
|
||||||
|
|
||||||
|
/* This is a bit more complex than one might think at first. pwquality_check() would like to know the
|
||||||
|
* old password to make security checks. We support arbitrary numbers of passwords however, hence we
|
||||||
|
* call the function once for each combination of old and new password. */
|
||||||
|
|
||||||
|
/* Iterate through all new passwords */
|
||||||
|
STRV_FOREACH(pp, secret->password) {
|
||||||
|
bool called = false;
|
||||||
|
char **old;
|
||||||
|
|
||||||
|
r = test_password_many(hr->hashed_password, *pp);
|
||||||
|
if (r < 0)
|
||||||
|
return r;
|
||||||
|
if (r == 0) /* This is an old password as it isn't listed in the hashedPassword field, skip it */
|
||||||
|
continue;
|
||||||
|
|
||||||
|
/* Check this password against all old passwords */
|
||||||
|
STRV_FOREACH(old, secret->password) {
|
||||||
|
|
||||||
|
if (streq(*pp, *old))
|
||||||
|
continue;
|
||||||
|
|
||||||
|
r = test_password_many(hr->hashed_password, *old);
|
||||||
|
if (r < 0)
|
||||||
|
return r;
|
||||||
|
if (r > 0) /* This is a new password, not suitable as old password */
|
||||||
|
continue;
|
||||||
|
|
||||||
|
r = sym_pwquality_check(pwq, *pp, *old, hr->user_name, &auxerror);
|
||||||
|
if (r < 0)
|
||||||
|
return sd_bus_error_setf(error, BUS_ERROR_LOW_PASSWORD_QUALITY, "Password too weak: %s",
|
||||||
|
sym_pwquality_strerror(buf, sizeof(buf), r, auxerror));
|
||||||
|
|
||||||
|
called = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (called)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
/* If there are no old passwords, let's call pwquality_check() without any. */
|
||||||
|
r = sym_pwquality_check(pwq, *pp, NULL, hr->user_name, &auxerror);
|
||||||
|
if (r < 0)
|
||||||
|
return sd_bus_error_setf(error, BUS_ERROR_LOW_PASSWORD_QUALITY, "Password too weak: %s",
|
||||||
|
sym_pwquality_strerror(buf, sizeof(buf), r, auxerror));
|
||||||
|
}
|
||||||
|
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
#else
|
||||||
|
|
||||||
|
int user_record_quality_check_password(
|
||||||
|
UserRecord *hr,
|
||||||
|
UserRecord *secret,
|
||||||
|
sd_bus_error *error) {
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif
|
|
@ -0,0 +1,7 @@
|
||||||
|
/* SPDX-License-Identifier: LGPL-2.1+ */
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include "sd-bus.h"
|
||||||
|
#include "user-record.h"
|
||||||
|
|
||||||
|
int user_record_quality_check_password(UserRecord *hr, UserRecord *secret, sd_bus_error *error);
|
|
@ -2573,10 +2573,10 @@ int main(int argc, char *argv[]) {
|
||||||
|
|
||||||
if (r > 0) {
|
if (r > 0) {
|
||||||
if (arg_follow)
|
if (arg_follow)
|
||||||
printf("-- Logs begin at %s. --\n",
|
printf("-- Journal begins at %s. --\n",
|
||||||
format_timestamp_maybe_utc(start_buf, sizeof(start_buf), start));
|
format_timestamp_maybe_utc(start_buf, sizeof(start_buf), start));
|
||||||
else
|
else
|
||||||
printf("-- Logs begin at %s, end at %s. --\n",
|
printf("-- Journal begins at %s, ends at %s. --\n",
|
||||||
format_timestamp_maybe_utc(start_buf, sizeof(start_buf), start),
|
format_timestamp_maybe_utc(start_buf, sizeof(start_buf), start),
|
||||||
format_timestamp_maybe_utc(end_buf, sizeof(end_buf), end));
|
format_timestamp_maybe_utc(end_buf, sizeof(end_buf), end));
|
||||||
}
|
}
|
||||||
|
|
|
@ -618,8 +618,6 @@ int cg_create_everywhere(CGroupMask supported, CGroupMask mask, const char *path
|
||||||
}
|
}
|
||||||
|
|
||||||
int cg_attach_everywhere(CGroupMask supported, const char *path, pid_t pid, cg_migrate_callback_t path_callback, void *userdata) {
|
int cg_attach_everywhere(CGroupMask supported, const char *path, pid_t pid, cg_migrate_callback_t path_callback, void *userdata) {
|
||||||
CGroupController c;
|
|
||||||
CGroupMask done;
|
|
||||||
int r;
|
int r;
|
||||||
|
|
||||||
r = cg_attach(SYSTEMD_CGROUP_CONTROLLER, path, pid);
|
r = cg_attach(SYSTEMD_CGROUP_CONTROLLER, path, pid);
|
||||||
|
@ -633,9 +631,9 @@ int cg_attach_everywhere(CGroupMask supported, const char *path, pid_t pid, cg_m
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
supported &= CGROUP_MASK_V1;
|
supported &= CGROUP_MASK_V1;
|
||||||
done = 0;
|
CGroupMask done = 0;
|
||||||
|
|
||||||
for (c = 0; c < _CGROUP_CONTROLLER_MAX; c++) {
|
for (CGroupController c = 0; c < _CGROUP_CONTROLLER_MAX; c++) {
|
||||||
CGroupMask bit = CGROUP_CONTROLLER_TO_MASK(c);
|
CGroupMask bit = CGROUP_CONTROLLER_TO_MASK(c);
|
||||||
const char *p = NULL;
|
const char *p = NULL;
|
||||||
|
|
||||||
|
|
|
@ -191,6 +191,8 @@ shared_sources = files('''
|
||||||
pretty-print.h
|
pretty-print.h
|
||||||
ptyfwd.c
|
ptyfwd.c
|
||||||
ptyfwd.h
|
ptyfwd.h
|
||||||
|
pwquality-util.c
|
||||||
|
pwquality-util.h
|
||||||
reboot-util.c
|
reboot-util.c
|
||||||
reboot-util.h
|
reboot-util.h
|
||||||
resize-fs.c
|
resize-fs.c
|
||||||
|
|
|
@ -0,0 +1,191 @@
|
||||||
|
/* SPDX-License-Identifier: LGPL-2.1+ */
|
||||||
|
|
||||||
|
#include <unistd.h>
|
||||||
|
|
||||||
|
#include "dlfcn-util.h"
|
||||||
|
#include "errno-util.h"
|
||||||
|
#include "log.h"
|
||||||
|
#include "macro.h"
|
||||||
|
#include "memory-util.h"
|
||||||
|
#include "pwquality-util.h"
|
||||||
|
#include "strv.h"
|
||||||
|
|
||||||
|
#if HAVE_PWQUALITY
|
||||||
|
|
||||||
|
static void *pwquality_dl = NULL;
|
||||||
|
|
||||||
|
int (*sym_pwquality_check)(pwquality_settings_t *pwq, const char *password, const char *oldpassword, const char *user, void **auxerror);
|
||||||
|
pwquality_settings_t *(*sym_pwquality_default_settings)(void);
|
||||||
|
void (*sym_pwquality_free_settings)(pwquality_settings_t *pwq);
|
||||||
|
int (*sym_pwquality_generate)(pwquality_settings_t *pwq, int entropy_bits, char **password);
|
||||||
|
int (*sym_pwquality_get_str_value)(pwquality_settings_t *pwq, int setting, const char **value);
|
||||||
|
int (*sym_pwquality_read_config)(pwquality_settings_t *pwq, const char *cfgfile, void **auxerror);
|
||||||
|
int (*sym_pwquality_set_int_value)(pwquality_settings_t *pwq, int setting, int value);
|
||||||
|
const char* (*sym_pwquality_strerror)(char *buf, size_t len, int errcode, void *auxerror);
|
||||||
|
|
||||||
|
int dlopen_pwquality(void) {
|
||||||
|
_cleanup_(dlclosep) void *dl = NULL;
|
||||||
|
int r;
|
||||||
|
|
||||||
|
if (pwquality_dl)
|
||||||
|
return 0; /* Already loaded */
|
||||||
|
|
||||||
|
dl = dlopen("libpwquality.so.1", RTLD_LAZY);
|
||||||
|
if (!dl)
|
||||||
|
return log_debug_errno(SYNTHETIC_ERRNO(EOPNOTSUPP),
|
||||||
|
"libpwquality support is not installed: %s", dlerror());
|
||||||
|
|
||||||
|
r = dlsym_many_and_warn(
|
||||||
|
dl,
|
||||||
|
LOG_DEBUG,
|
||||||
|
&sym_pwquality_check, "pwquality_check",
|
||||||
|
&sym_pwquality_default_settings, "pwquality_default_settings",
|
||||||
|
&sym_pwquality_free_settings, "pwquality_free_settings",
|
||||||
|
&sym_pwquality_generate, "pwquality_generate",
|
||||||
|
&sym_pwquality_get_str_value, "pwquality_get_str_value",
|
||||||
|
&sym_pwquality_read_config, "pwquality_read_config",
|
||||||
|
&sym_pwquality_set_int_value, "pwquality_set_int_value",
|
||||||
|
&sym_pwquality_strerror, "pwquality_strerror",
|
||||||
|
NULL);
|
||||||
|
if (r < 0)
|
||||||
|
return r;
|
||||||
|
|
||||||
|
/* Note that we never release the reference here, because there's no real reason to, after all this
|
||||||
|
* was traditionally a regular shared library dependency which lives forever too. */
|
||||||
|
pwquality_dl = TAKE_PTR(dl);
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
void pwq_maybe_disable_dictionary(pwquality_settings_t *pwq) {
|
||||||
|
char buf[PWQ_MAX_ERROR_MESSAGE_LEN];
|
||||||
|
const char *path;
|
||||||
|
int r;
|
||||||
|
|
||||||
|
assert(pwq);
|
||||||
|
|
||||||
|
r = sym_pwquality_get_str_value(pwq, PWQ_SETTING_DICT_PATH, &path);
|
||||||
|
if (r < 0) {
|
||||||
|
log_debug("Failed to read libpwquality dictionary path, ignoring: %s",
|
||||||
|
sym_pwquality_strerror(buf, sizeof(buf), r, NULL));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// REMOVE THIS AS SOON AS https://github.com/libpwquality/libpwquality/pull/21 IS MERGED AND RELEASED
|
||||||
|
if (isempty(path))
|
||||||
|
path = "/usr/share/cracklib/pw_dict.pwd.gz";
|
||||||
|
|
||||||
|
if (isempty(path)) {
|
||||||
|
log_debug("Weird, no dictionary file configured, ignoring.");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (access(path, F_OK) >= 0)
|
||||||
|
return;
|
||||||
|
|
||||||
|
if (errno != ENOENT) {
|
||||||
|
log_debug_errno(errno, "Failed to check if dictionary file %s exists, ignoring: %m", path);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
r = sym_pwquality_set_int_value(pwq, PWQ_SETTING_DICT_CHECK, 0);
|
||||||
|
if (r < 0)
|
||||||
|
log_debug("Failed to disable libpwquality dictionary check, ignoring: %s",
|
||||||
|
sym_pwquality_strerror(buf, sizeof(buf), r, NULL));
|
||||||
|
}
|
||||||
|
|
||||||
|
int pwq_allocate_context(pwquality_settings_t **ret) {
|
||||||
|
_cleanup_(sym_pwquality_free_settingsp) pwquality_settings_t *pwq = NULL;
|
||||||
|
char buf[PWQ_MAX_ERROR_MESSAGE_LEN];
|
||||||
|
void *auxerror;
|
||||||
|
int r;
|
||||||
|
|
||||||
|
assert(ret);
|
||||||
|
|
||||||
|
r = dlopen_pwquality();
|
||||||
|
if (r < 0)
|
||||||
|
return r;
|
||||||
|
|
||||||
|
pwq = sym_pwquality_default_settings();
|
||||||
|
if (!pwq)
|
||||||
|
return -ENOMEM;
|
||||||
|
|
||||||
|
r = sym_pwquality_read_config(pwq, NULL, &auxerror);
|
||||||
|
if (r < 0)
|
||||||
|
log_debug("Failed to read libpwquality configuration, ignoring: %s",
|
||||||
|
sym_pwquality_strerror(buf, sizeof(buf), r, auxerror));
|
||||||
|
|
||||||
|
pwq_maybe_disable_dictionary(pwq);
|
||||||
|
|
||||||
|
*ret = TAKE_PTR(pwq);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
#define N_SUGGESTIONS 6
|
||||||
|
|
||||||
|
int suggest_passwords(void) {
|
||||||
|
_cleanup_(sym_pwquality_free_settingsp) pwquality_settings_t *pwq = NULL;
|
||||||
|
_cleanup_strv_free_erase_ char **suggestions = NULL;
|
||||||
|
_cleanup_(erase_and_freep) char *joined = NULL;
|
||||||
|
char buf[PWQ_MAX_ERROR_MESSAGE_LEN];
|
||||||
|
size_t i;
|
||||||
|
int r;
|
||||||
|
|
||||||
|
r = pwq_allocate_context(&pwq);
|
||||||
|
if (ERRNO_IS_NOT_SUPPORTED(r))
|
||||||
|
return 0;
|
||||||
|
if (r < 0)
|
||||||
|
return log_error_errno(r, "Failed to allocate libpwquality context: %m");
|
||||||
|
|
||||||
|
suggestions = new0(char*, N_SUGGESTIONS+1);
|
||||||
|
if (!suggestions)
|
||||||
|
return log_oom();
|
||||||
|
|
||||||
|
for (i = 0; i < N_SUGGESTIONS; i++) {
|
||||||
|
r = sym_pwquality_generate(pwq, 64, suggestions + i);
|
||||||
|
if (r < 0)
|
||||||
|
return log_error_errno(SYNTHETIC_ERRNO(EIO), "Failed to generate password, ignoring: %s",
|
||||||
|
sym_pwquality_strerror(buf, sizeof(buf), r, NULL));
|
||||||
|
}
|
||||||
|
|
||||||
|
joined = strv_join(suggestions, " ");
|
||||||
|
if (!joined)
|
||||||
|
return log_oom();
|
||||||
|
|
||||||
|
log_info("Password suggestions: %s", joined);
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
int quality_check_password(const char *password, const char *username, char **ret_error) {
|
||||||
|
_cleanup_(sym_pwquality_free_settingsp) pwquality_settings_t *pwq = NULL;
|
||||||
|
char buf[PWQ_MAX_ERROR_MESSAGE_LEN];
|
||||||
|
void *auxerror;
|
||||||
|
int r;
|
||||||
|
|
||||||
|
assert(password);
|
||||||
|
|
||||||
|
r = pwq_allocate_context(&pwq);
|
||||||
|
if (ERRNO_IS_NOT_SUPPORTED(r))
|
||||||
|
return 0;
|
||||||
|
if (r < 0)
|
||||||
|
return log_debug_errno(r, "Failed to allocate libpwquality context: %m");
|
||||||
|
|
||||||
|
r = sym_pwquality_check(pwq, password, NULL, username, &auxerror);
|
||||||
|
if (r < 0) {
|
||||||
|
|
||||||
|
if (ret_error) {
|
||||||
|
_cleanup_free_ char *e = NULL;
|
||||||
|
|
||||||
|
e = strdup(sym_pwquality_strerror(buf, sizeof(buf), r, auxerror));
|
||||||
|
if (!e)
|
||||||
|
return -ENOMEM;
|
||||||
|
|
||||||
|
*ret_error = TAKE_PTR(e);
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0; /* all bad */
|
||||||
|
}
|
||||||
|
|
||||||
|
return 1; /* all good */
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif
|
|
@ -0,0 +1,41 @@
|
||||||
|
/* SPDX-License-Identifier: LGPL-2.1+ */
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include "macro.h"
|
||||||
|
|
||||||
|
#if HAVE_PWQUALITY
|
||||||
|
/* pwquality.h uses size_t but doesn't include sys/types.h on its own */
|
||||||
|
#include <sys/types.h>
|
||||||
|
#include <pwquality.h>
|
||||||
|
|
||||||
|
extern int (*sym_pwquality_check)(pwquality_settings_t *pwq, const char *password, const char *oldpassword, const char *user, void **auxerror);
|
||||||
|
extern pwquality_settings_t *(*sym_pwquality_default_settings)(void);
|
||||||
|
extern void (*sym_pwquality_free_settings)(pwquality_settings_t *pwq);
|
||||||
|
extern int (*sym_pwquality_generate)(pwquality_settings_t *pwq, int entropy_bits, char **password);
|
||||||
|
extern int (*sym_pwquality_get_str_value)(pwquality_settings_t *pwq, int setting, const char **value);
|
||||||
|
extern int (*sym_pwquality_read_config)(pwquality_settings_t *pwq, const char *cfgfile, void **auxerror);
|
||||||
|
extern int (*sym_pwquality_set_int_value)(pwquality_settings_t *pwq, int setting, int value);
|
||||||
|
extern const char* (*sym_pwquality_strerror)(char *buf, size_t len, int errcode, void *auxerror);
|
||||||
|
|
||||||
|
int dlopen_pwquality(void);
|
||||||
|
|
||||||
|
DEFINE_TRIVIAL_CLEANUP_FUNC(pwquality_settings_t*, sym_pwquality_free_settings);
|
||||||
|
|
||||||
|
void pwq_maybe_disable_dictionary(pwquality_settings_t *pwq);
|
||||||
|
int pwq_allocate_context(pwquality_settings_t **ret);
|
||||||
|
int suggest_passwords(void);
|
||||||
|
int quality_check_password(const char *password, const char *username, char **ret_error);
|
||||||
|
|
||||||
|
#else
|
||||||
|
|
||||||
|
static inline int suggest_passwords(void) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline int quality_check_password(const char *password, const char *username, char **ret_error) {
|
||||||
|
if (ret_error)
|
||||||
|
*ret_error = NULL;
|
||||||
|
return 1; /* all good */
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif
|
|
@ -1581,7 +1581,7 @@ UserStorage user_record_storage(UserRecord *h) {
|
||||||
const char *user_record_file_system_type(UserRecord *h) {
|
const char *user_record_file_system_type(UserRecord *h) {
|
||||||
assert(h);
|
assert(h);
|
||||||
|
|
||||||
return h->file_system_type ?: "ext4";
|
return h->file_system_type ?: "btrfs";
|
||||||
}
|
}
|
||||||
|
|
||||||
const char *user_record_skeleton_directory(UserRecord *h) {
|
const char *user_record_skeleton_directory(UserRecord *h) {
|
||||||
|
|
Loading…
Reference in New Issue