Compare commits

..

No commits in common. "caf6bd166f6521e1e33a25c39bb2e1b05d61b733" and "e71f5585b9b0580428f9530d0a485265c9c25165" have entirely different histories.

29 changed files with 263 additions and 437 deletions

21
NEWS
View File

@ -114,9 +114,7 @@ CHANGES WITH 246:
* tmpfs mounts automatically created by systemd (/tmp, /run, /dev/shm,
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.). Please note
that the implicit kernel default is 50% too, so there is no change
in the size limit for /tmp and /dev/shm.
/tmp and /dev/shm, 10% of RAM for other mounts, etc.)
* nss-mymachines lost support for resolution of users and groups, and
now only does resolution of hostnames. This functionality is now
@ -158,17 +156,12 @@ CHANGES WITH 246:
now automatically set to "Y" at boot, in order to enable pstore
generation for collection with systemd-pstore.
* We provide a set of udev rules to enable auto-suspend on PCI and USB
devices that were tested to currectly support it. Previously, this
was distributed as a set of udev rules, but has now been replaced by
by a set of hwdb entries (and a much shorter udev rule to take action
if the device modalias matches one of the new hwdb entries).
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).
* A new 'hwdb' file has been added that collects information about PCI
and USB devices that correctly support auto-suspend, on top of the
databases for this we import from 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
as a corresponding kernel command line option udev.timeout_signal=.

4
TODO
View File

@ -87,7 +87,8 @@ Features:
* make us use dynamically fewer deps for containers in general purpose distros:
o turn into dlopen() deps:
- libidn2 (always)
- libpwquality (always) - only relevant for homed, and maybe soon
firstboot
- elfutils (always)
- p11-kit-trust (always)
- kmod-libs (only when called from PID 1)
@ -364,6 +365,7 @@ Features:
- fingerprint authentication, pattern authentication, …
- make sure "classic" user records can also be managed by homed
- make size of $XDG_RUNTIME_DIR configurable in user record
- reuse pwquality magic in firstboot
- query password from kernel keyring first
- 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

View File

@ -566,8 +566,8 @@
<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
directory LUKS2 container. One of <literal>btrfs</literal>, <literal>ext4</literal>,
<literal>xfs</literal>. If not specified
directory LUKS2 container. One of <literal>ext4</literal>, <literal>xfs</literal>,
<literal>btrfs</literal>. If not specified
<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
its support for file system resizing is too limited.</para></listitem>

View File

@ -63,9 +63,9 @@
<varlistentry>
<term><varname>DefaultFileSystemType=</varname></term>
<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>btrfs</literal>,
<literal>ext4</literal> or <literal>xfs</literal>. If not specified defaults to
<literal>btrfs</literal>. This setting has no effect if a different storage mechanism is used. The
system to use inside the user's LUKS volume. Takes one of <literal>ext4</literal>,
<literal>xfs</literal> or <literal>btrfs</literal>. If not specified defaults to
<literal>ext4</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
precedence.</para></listitem>
</varlistentry>

View File

@ -453,7 +453,7 @@
<term><option>--quiet</option></term>
<listitem><para>Suppresses all informational messages
(i.e. "-- Journal begins at …", "-- Reboot --"),
(i.e. "-- Logs begin at …", "-- Reboot --"),
any warning messages regarding
inaccessible system journals when run as a normal
user.</para></listitem>

View File

@ -463,11 +463,11 @@ Mon Dec 8 20:44:24 KST 2014
Running as unit: run-71.timer
Will run service as unit: run-71.service
# journalctl -b -u run-71.timer
-- Journal begins at Fri 2014-12-05 19:09:21 KST, ends at Mon 2014-12-08 20:44:54 KST. --
-- Logs begin at Fri 2014-12-05 19:09:21 KST, end 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]: Started /bin/touch /tmp/foo.
# journalctl -b -u run-71.service
-- Journal begins at Fri 2014-12-05 19:09:21 KST, ends at Mon 2014-12-08 20:44:54 KST. --
-- Logs begin at Fri 2014-12-05 19:09:21 KST, end 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]: Started /bin/touch /tmp/foo.</programlisting>
</example>

View File

@ -2174,7 +2174,8 @@ if conf.get('ENABLE_HOMED') == 1
link_with : [libshared],
dependencies : [threads,
libcrypt,
libopenssl],
libopenssl,
libpwquality],
install_rpath : rootlibexecdir,
install : true,
install_dir : rootlibexecdir)
@ -2188,7 +2189,8 @@ if conf.get('ENABLE_HOMED') == 1
libcrypt,
libopenssl,
libp11kit,
libfido2],
libfido2,
libpwquality],
install_rpath : rootlibexecdir,
install : true,
install_dir : rootbindir)

View File

@ -139,7 +139,7 @@ _homectl() {
comps=$(cat /etc/shells)
;;
--fs-type)
comps='btrfs ext4 xfs'
comps='ext4 xfs btrsf'
;;
--cifs-user-name)
comps=$(compgen -A user -- "$cur" )

View File

@ -493,7 +493,7 @@ static int assess_system_call_architectures(
#if HAVE_SECCOMP
static bool syscall_names_in_filter(Set *s, bool allow_list, const SyscallFilterSet *f, const char **ret_offending_syscall) {
static bool syscall_names_in_filter(Set *s, bool allow_list, const SyscallFilterSet *f) {
const char *syscall;
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;
assert_se(g = syscall_filter_set_find(syscall));
if (syscall_names_in_filter(s, allow_list, g, ret_offending_syscall))
if (syscall_names_in_filter(s, allow_list, g))
return true; /* bad! */
continue;
@ -516,13 +516,10 @@ static bool syscall_names_in_filter(Set *s, bool allow_list, const SyscallFilter
if (set_contains(s, syscall) == allow_list) {
log_debug("Offending syscall filter item: %s", syscall);
if (ret_offending_syscall)
*ret_offending_syscall = syscall;
return true; /* bad! */
}
}
*ret_offending_syscall = NULL;
return false;
}
@ -533,49 +530,43 @@ static int assess_system_call_filter(
uint64_t *ret_badness,
char **ret_description) {
const SyscallFilterSet *f;
char *d = NULL;
uint64_t b;
assert(a);
assert(info);
assert(ret_badness);
assert(ret_description);
assert(a->parameter < _SYSCALL_FILTER_SET_MAX);
const SyscallFilterSet *f = syscall_filter_sets + a->parameter;
char *d = NULL;
uint64_t b;
f = syscall_filter_sets + a->parameter;
if (!info->system_call_filter_allow_list && set_isempty(info->system_call_filter)) {
d = strdup("Service does not filter system calls");
b = 10;
} else {
bool bad;
const char *offender = NULL;
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, &offender);
bad = syscall_names_in_filter(info->system_call_filter, info->system_call_filter_allow_list, f);
log_debug("Result: %s", bad ? "bad" : "good");
if (info->system_call_filter_allow_list) {
if (bad) {
(void) asprintf(&d, "System call allow list defined for service, and %s is included "
"(e.g. %s is allowed)",
f->name, offender);
(void) asprintf(&d, "System call allow list defined for service, and %s is included", f->name);
b = 9;
} 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;
}
} else {
if (bad) {
(void) asprintf(&d, "System call deny list defined for service, and %s is not included "
"(e.g. %s is allowed)",
f->name, offender);
(void) asprintf(&d, "System call deny list defined for service, and %s is not included", f->name);
b = 10;
} else {
(void) asprintf(&d, "System call deny list defined for service, and %s is included",
f->name);
b = 0;
(void) asprintf(&d, "System call deny list defined for service, and %s is included", f->name);
b = 5;
}
}
}

View File

@ -135,8 +135,8 @@ char *strjoin_real(const char *x, ...) _sentinel_;
({ \
const char *_appendees_[] = { a, __VA_ARGS__ }; \
char *_d_, *_p_; \
size_t _len_ = 0; \
size_t _i_; \
size_t _len_ = 0; \
size_t _i_; \
for (_i_ = 0; _i_ < ELEMENTSOF(_appendees_) && _appendees_[_i_]; _i_++) \
_len_ += strlen(_appendees_[_i_]); \
_p_ = _d_ = newa(char, _len_ + 1); \
@ -152,6 +152,7 @@ char *delete_trailing_chars(char *s, const char *bad);
char *truncate_nl(char *s);
static inline char *skip_leading_chars(const char *s, const char *bad) {
if (!s)
return NULL;
@ -230,9 +231,11 @@ REENABLE_WARNING;
/* Like startswith(), but operates on arbitrary memory blocks */
static inline void *memory_startswith(const void *p, size_t sz, const char *token) {
size_t n;
assert(token);
size_t n = strlen(token);
n = strlen(token);
if (sz < n)
return NULL;
@ -248,17 +251,20 @@ static inline void *memory_startswith(const void *p, size_t sz, const char *toke
* It works only for ASCII strings.
*/
static inline void *memory_startswith_no_case(const void *p, size_t sz, const char *token) {
size_t n, i;
assert(token);
size_t n = strlen(token);
n = strlen(token);
if (sz < n)
return NULL;
assert(p);
for (size_t i = 0; i < n; i++)
for (i = 0; i < n; i++) {
if (ascii_tolower(((char *)p)[i]) != ascii_tolower(token[i]))
return NULL;
}
return (uint8_t*) p + n;
}

View File

@ -123,7 +123,7 @@ int utf8_encoded_to_unichar(const char *str, char32_t *ret_unichar) {
return 0;
}
bool utf8_is_printable_newline(const char* str, size_t length, bool allow_newline) {
bool utf8_is_printable_newline(const char* str, size_t length, bool newline) {
const char *p;
assert(str);
@ -140,7 +140,7 @@ bool utf8_is_printable_newline(const char* str, size_t length, bool allow_newlin
r = utf8_encoded_to_unichar(p, &val);
if (r < 0 ||
unichar_is_control(val) ||
(!allow_newline && val == '\n'))
(!newline && val == '\n'))
return false;
length -= encoded_len;

View File

@ -18,7 +18,7 @@ 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);
bool utf8_is_printable_newline(const char* str, size_t length, bool allow_newline) _pure_;
bool utf8_is_printable_newline(const char* str, size_t length, bool newline) _pure_;
#define utf8_is_printable(str, length) utf8_is_printable_newline(str, length, true)
char *utf8_escape_invalid(const char *s);

View File

@ -28,7 +28,6 @@
#include "path-util.h"
#include "pretty-print.h"
#include "proc-cmdline.h"
#include "pwquality-util.h"
#include "random-util.h"
#include "string-util.h"
#include "strv.h"
@ -569,11 +568,8 @@ static int prompt_root_password(void) {
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:");
suggest_passwords();
for (;;) {
_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);
if (r < 0)
@ -587,12 +583,6 @@ static int prompt_root_password(void) {
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);
if (r < 0)
return log_error_errno(r, "Failed to query root password: %m");

View File

@ -30,7 +30,6 @@
#include "rlimit-util.h"
#include "spawn-polkit-agent.h"
#include "terminal-util.h"
#include "user-record-pwquality.h"
#include "user-record-show.h"
#include "user-record-util.h"
#include "user-record.h"
@ -1098,7 +1097,7 @@ static int create_home(int argc, char *argv[], void *userdata) {
/* If password quality enforcement is disabled, let's at least warn client side */
r = user_record_quality_check_password(hr, hr, &error);
r = quality_check_password(hr, hr, &error);
if (r < 0)
log_warning_errno(r, "Specified password does not pass quality checks (%s), proceeding anyway.", bus_error_message(&error, r));
}
@ -1956,7 +1955,7 @@ static int help(int argc, char *argv[], void *userdata) {
" --image-path=PATH Path to image file/directory\n"
"\n%4$sLUKS Storage User Record Properties:%5$s\n"
" --fs-type=TYPE File system type to use in case of luks\n"
" storage (btrfs, ext4, xfs)\n"
" storage (ext4, xfs, btrfs)\n"
" --luks-discard=BOOL Whether to use 'discard' feature of file system\n"
" when activated (mounted)\n"
" --luks-offline-discard=BOOL\n"

View File

@ -33,7 +33,6 @@
#include "strv.h"
#include "user-record-sign.h"
#include "user-record-util.h"
#include "user-record-pwquality.h"
#include "user-record.h"
#include "user-util.h"
@ -1290,7 +1289,7 @@ int home_create(Home *h, UserRecord *secret, sd_bus_error *error) {
if (h->record->enforce_password_policy == false)
log_debug("Password quality check turned off for account, skipping.");
else {
r = user_record_quality_check_password(h->record, secret, error);
r = quality_check_password(h->record, secret, error);
if (r < 0)
return r;
}
@ -1641,7 +1640,7 @@ int home_passwd(Home *h,
if (c->enforce_password_policy == false)
log_debug("Password quality check turned off for account, skipping.");
else {
r = user_record_quality_check_password(c, merged_secret, error);
r = quality_check_password(c, merged_secret, error);
if (r < 0)
return r;
}

View File

@ -512,8 +512,6 @@ static int search_quota(uid_t uid, const char *exclude_quota_path) {
if (r < 0) {
if (ERRNO_IS_NOT_SUPPORTED(r))
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
log_warning_errno(r, "Failed to query quota on %s, ignoring: %m", where);

View File

@ -13,4 +13,4 @@
[Home]
#DefaultStorage=
#DefaultFileSystemType=btrfs
#DefaultFileSystemType=ext4

View File

@ -1110,9 +1110,7 @@ int home_prepare_luks(
if (fstat(fd, &st) < 0)
return log_error_errno(errno, "Failed to fstat() image file: %m");
if (!S_ISREG(st.st_mode) && !S_ISBLK(st.st_mode))
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);
return log_error_errno(errno, "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);
if (r < 0)
@ -2017,8 +2015,7 @@ int home_create_luks(
r = chattr_fd(image_fd, FS_NOCOW_FL, FS_NOCOW_FL, NULL);
if (r < 0)
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);
log_warning_errno(r, "Failed to set file attributes on %s, ignoring: %m", temporary_image_path);
r = home_truncate(h, image_fd, temporary_image_path, host_size);
if (r < 0)
@ -2167,9 +2164,6 @@ int home_create_luks(
goto fail;
}
crypt_free(cd);
cd = NULL;
dm_activated = false;
loop = loop_device_unref(loop);
@ -2180,22 +2174,8 @@ int home_create_luks(
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)
(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
* lock that ensures udev doesn't interfere with what we are doing */

View File

@ -50,8 +50,8 @@ systemd_homed_sources = files('''
homed-varlink.c
homed-varlink.h
homed.c
user-record-pwquality.c
user-record-pwquality.h
pwquality-util.c
pwquality-util.h
user-record-sign.c
user-record-sign.h
user-record-util.c
@ -74,8 +74,8 @@ homectl_sources = files('''
homectl-pkcs11.c
homectl-pkcs11.h
homectl.c
user-record-pwquality.c
user-record-pwquality.h
pwquality-util.c
pwquality-util.h
user-record-util.c
user-record-util.h
'''.split())

186
src/home/pwquality-util.c Normal file
View File

@ -0,0 +1,186 @@
/* 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

View File

@ -0,0 +1,9 @@
/* 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);

View File

@ -1,90 +0,0 @@
/* 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

View File

@ -1,7 +0,0 @@
/* 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);

View File

@ -2573,10 +2573,10 @@ int main(int argc, char *argv[]) {
if (r > 0) {
if (arg_follow)
printf("-- Journal begins at %s. --\n",
printf("-- Logs begin at %s. --\n",
format_timestamp_maybe_utc(start_buf, sizeof(start_buf), start));
else
printf("-- Journal begins at %s, ends at %s. --\n",
printf("-- Logs begin at %s, end at %s. --\n",
format_timestamp_maybe_utc(start_buf, sizeof(start_buf), start),
format_timestamp_maybe_utc(end_buf, sizeof(end_buf), end));
}

View File

@ -618,6 +618,8 @@ 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) {
CGroupController c;
CGroupMask done;
int r;
r = cg_attach(SYSTEMD_CGROUP_CONTROLLER, path, pid);
@ -631,9 +633,9 @@ int cg_attach_everywhere(CGroupMask supported, const char *path, pid_t pid, cg_m
return 0;
supported &= CGROUP_MASK_V1;
CGroupMask done = 0;
done = 0;
for (CGroupController c = 0; c < _CGROUP_CONTROLLER_MAX; c++) {
for (c = 0; c < _CGROUP_CONTROLLER_MAX; c++) {
CGroupMask bit = CGROUP_CONTROLLER_TO_MASK(c);
const char *p = NULL;

View File

@ -191,8 +191,6 @@ shared_sources = files('''
pretty-print.h
ptyfwd.c
ptyfwd.h
pwquality-util.c
pwquality-util.h
reboot-util.c
reboot-util.h
resize-fs.c

View File

@ -1,191 +0,0 @@
/* 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

View File

@ -1,41 +0,0 @@
/* 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

View File

@ -1581,7 +1581,7 @@ UserStorage user_record_storage(UserRecord *h) {
const char *user_record_file_system_type(UserRecord *h) {
assert(h);
return h->file_system_type ?: "btrfs";
return h->file_system_type ?: "ext4";
}
const char *user_record_skeleton_directory(UserRecord *h) {