mirror of
https://github.com/systemd/systemd
synced 2026-03-19 11:34:46 +01:00
Compare commits
13 Commits
431fc656bc
...
5fcca42f18
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
5fcca42f18 | ||
|
|
944ae1286b | ||
|
|
2553c53730 | ||
|
|
6d2c9c2203 | ||
|
|
fe3c790f71 | ||
|
|
508dc4c3fa | ||
|
|
d0b224f845 | ||
|
|
8de783a288 | ||
|
|
5863641bb7 | ||
|
|
8608d2e910 | ||
|
|
d5267b2275 | ||
|
|
b26406c9c3 | ||
|
|
d274748160 |
2
README
2
README
@ -212,7 +212,7 @@ REQUIREMENTS:
|
|||||||
newer though. TL;DR: turn audit off, still.
|
newer though. TL;DR: turn audit off, still.
|
||||||
|
|
||||||
glibc >= 2.31
|
glibc >= 2.31
|
||||||
libxcrypt or glibc (<= 2.38 built with --enable-crypt)
|
libxcrypt >= 4.4.0 (optional)
|
||||||
libmount >= 2.30 (from util-linux)
|
libmount >= 2.30 (from util-linux)
|
||||||
(util-linux *must* be built without --enable-libmount-support-mtab)
|
(util-linux *must* be built without --enable-libmount-support-mtab)
|
||||||
libseccomp >= 2.4.0 (optional)
|
libseccomp >= 2.4.0 (optional)
|
||||||
|
|||||||
4
TODO
4
TODO
@ -137,6 +137,10 @@ Deprecations and removals:
|
|||||||
|
|
||||||
Features:
|
Features:
|
||||||
|
|
||||||
|
* systemd-sysext: add "exec" command or so that is a bit like "refresh" but
|
||||||
|
runs it in a new namespace and then just executes the selected binary within
|
||||||
|
it. Could be useful to run one-off binaries inside a sysext as a CLI tool.
|
||||||
|
|
||||||
* systemd-repart: implement Integrity=data/meta and Integrity=inline for non-LUKS
|
* systemd-repart: implement Integrity=data/meta and Integrity=inline for non-LUKS
|
||||||
case. Currently, only Integrity=inline combined with Encrypt= is implemented
|
case. Currently, only Integrity=inline combined with Encrypt= is implemented
|
||||||
and uses libcryptsetup features. Add support for plain dm-integrity setups when
|
and uses libcryptsetup features. Add support for plain dm-integrity setups when
|
||||||
|
|||||||
39
meson.build
39
meson.build
@ -685,15 +685,6 @@ conf.set('GPERF_LEN_TYPE', gperf_len_type,
|
|||||||
|
|
||||||
#####################################################################
|
#####################################################################
|
||||||
|
|
||||||
foreach header : [
|
|
||||||
'crypt.h',
|
|
||||||
]
|
|
||||||
|
|
||||||
if not cc.has_header(header)
|
|
||||||
error(f'Header file @header@ not found')
|
|
||||||
endif
|
|
||||||
endforeach
|
|
||||||
|
|
||||||
foreach header : [
|
foreach header : [
|
||||||
'gshadow.h',
|
'gshadow.h',
|
||||||
'nss.h',
|
'nss.h',
|
||||||
@ -1046,22 +1037,18 @@ else
|
|||||||
libatomic = []
|
libatomic = []
|
||||||
endif
|
endif
|
||||||
|
|
||||||
libcrypt = dependency('libcrypt', 'libxcrypt', required : false)
|
if get_option('libc') == 'musl'
|
||||||
if not libcrypt.found()
|
libcrypt = []
|
||||||
# fallback to use find_library() if libcrypt is provided by glibc, e.g. for LibreELEC.
|
libcrypt_cflags = []
|
||||||
libcrypt = cc.find_library('crypt')
|
have = get_option('libcrypt').allowed()
|
||||||
|
else
|
||||||
|
libcrypt = dependency('libcrypt', 'libxcrypt',
|
||||||
|
required : get_option('libcrypt'),
|
||||||
|
version : '>=4.4.0')
|
||||||
|
libcrypt_cflags = libcrypt.partial_dependency(includes: true, compile_args: true)
|
||||||
|
have = libcrypt.found()
|
||||||
endif
|
endif
|
||||||
|
conf.set10('HAVE_LIBCRYPT', have)
|
||||||
foreach func : [
|
|
||||||
'crypt_ra', # since libxcrypt-4.0.0
|
|
||||||
'crypt_gensalt_ra', # since libxcrypt-4.0.0
|
|
||||||
'crypt_preferred_method', # since libxcrypt-4.4.0
|
|
||||||
]
|
|
||||||
|
|
||||||
have = cc.has_function(func, prefix : '''#include <crypt.h>''', args : '-D_GNU_SOURCE',
|
|
||||||
dependencies : libcrypt)
|
|
||||||
conf.set10('HAVE_' + func.to_upper(), have)
|
|
||||||
endforeach
|
|
||||||
|
|
||||||
bpf_framework = get_option('bpf-framework')
|
bpf_framework = get_option('bpf-framework')
|
||||||
bpf_compiler = get_option('bpf-compiler')
|
bpf_compiler = get_option('bpf-compiler')
|
||||||
@ -1594,10 +1581,11 @@ conf.set10('ENABLE_SYSUPDATED', have2)
|
|||||||
conf.set10('ENABLE_STORAGETM', get_option('storagetm'))
|
conf.set10('ENABLE_STORAGETM', get_option('storagetm'))
|
||||||
|
|
||||||
have = get_option('homed').require(
|
have = get_option('homed').require(
|
||||||
|
conf.get('HAVE_LIBCRYPT') == 1 and
|
||||||
conf.get('HAVE_OPENSSL') == 1 and
|
conf.get('HAVE_OPENSSL') == 1 and
|
||||||
conf.get('HAVE_LIBFDISK') == 1 and
|
conf.get('HAVE_LIBFDISK') == 1 and
|
||||||
conf.get('HAVE_LIBCRYPTSETUP') == 1,
|
conf.get('HAVE_LIBCRYPTSETUP') == 1,
|
||||||
error_message : 'openssl, fdisk and libcryptsetup required').allowed()
|
error_message : 'libcrypt, openssl, fdisk, and libcryptsetup required').allowed()
|
||||||
conf.set10('ENABLE_HOMED', have)
|
conf.set10('ENABLE_HOMED', have)
|
||||||
|
|
||||||
have = have and conf.get('HAVE_PAM') == 1
|
have = have and conf.get('HAVE_PAM') == 1
|
||||||
@ -3124,6 +3112,7 @@ foreach tuple : [
|
|||||||
['gnutls'],
|
['gnutls'],
|
||||||
['libarchive'],
|
['libarchive'],
|
||||||
['libbpf'],
|
['libbpf'],
|
||||||
|
['libcrypt'],
|
||||||
['libcryptsetup'],
|
['libcryptsetup'],
|
||||||
['libcryptsetup-plugins'],
|
['libcryptsetup-plugins'],
|
||||||
['libcurl'],
|
['libcurl'],
|
||||||
|
|||||||
@ -426,6 +426,8 @@ option('pwquality', type : 'feature', deprecated : { 'true' : 'enabled', 'false'
|
|||||||
description : 'libpwquality support')
|
description : 'libpwquality support')
|
||||||
option('microhttpd', type : 'feature', deprecated : { 'true' : 'enabled', 'false' : 'disabled' },
|
option('microhttpd', type : 'feature', deprecated : { 'true' : 'enabled', 'false' : 'disabled' },
|
||||||
description : 'libµhttpd support')
|
description : 'libµhttpd support')
|
||||||
|
option('libcrypt', type : 'feature',
|
||||||
|
description : 'libcrypt/libxcrypt support')
|
||||||
option('libcryptsetup', type : 'feature', deprecated : { 'true' : 'enabled', 'false' : 'disabled' },
|
option('libcryptsetup', type : 'feature', deprecated : { 'true' : 'enabled', 'false' : 'disabled' },
|
||||||
description : 'libcryptsetup support')
|
description : 'libcryptsetup support')
|
||||||
option('libcryptsetup-plugins', type : 'feature', deprecated : { 'true' : 'enabled', 'false' : 'disabled' },
|
option('libcryptsetup-plugins', type : 'feature', deprecated : { 'true' : 'enabled', 'false' : 'disabled' },
|
||||||
|
|||||||
@ -1192,18 +1192,18 @@ static int ask_password_conv(
|
|||||||
return PAM_SUCCESS;
|
return PAM_SUCCESS;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int pam_close_session_and_delete_credentials(pam_handle_t *handle, int flags) {
|
static int pam_close_session_and_delete_credentials(pam_handle_t *pamh, int flags) {
|
||||||
int r, s;
|
int r, s;
|
||||||
|
|
||||||
assert(handle);
|
assert(pamh);
|
||||||
|
|
||||||
r = sym_pam_close_session(handle, flags);
|
r = sym_pam_close_session(pamh, flags);
|
||||||
if (r != PAM_SUCCESS)
|
if (r != PAM_SUCCESS)
|
||||||
pam_syslog_pam_error(handle, LOG_DEBUG, r, "pam_close_session() failed: @PAMERR@");
|
pam_syslog_pam_error(pamh, LOG_DEBUG, r, "pam_close_session() failed: @PAMERR@");
|
||||||
|
|
||||||
s = sym_pam_setcred(handle, PAM_DELETE_CRED | flags);
|
s = sym_pam_setcred(pamh, PAM_DELETE_CRED | flags);
|
||||||
if (s != PAM_SUCCESS)
|
if (s != PAM_SUCCESS)
|
||||||
pam_syslog_pam_error(handle, LOG_DEBUG, r, "pam_setcred(PAM_DELETE_CRED) failed: @PAMERR@");
|
pam_syslog_pam_error(pamh, LOG_DEBUG, r, "pam_setcred(PAM_DELETE_CRED) failed: @PAMERR@");
|
||||||
|
|
||||||
return r != PAM_SUCCESS ? r : s;
|
return r != PAM_SUCCESS ? r : s;
|
||||||
}
|
}
|
||||||
@ -1339,7 +1339,7 @@ static int setup_pam(
|
|||||||
_cleanup_(barrier_destroy) Barrier barrier = BARRIER_NULL;
|
_cleanup_(barrier_destroy) Barrier barrier = BARRIER_NULL;
|
||||||
_cleanup_strv_free_ char **e = NULL;
|
_cleanup_strv_free_ char **e = NULL;
|
||||||
_cleanup_free_ char *tty = NULL;
|
_cleanup_free_ char *tty = NULL;
|
||||||
pam_handle_t *handle = NULL;
|
pam_handle_t *pamh = NULL;
|
||||||
sigset_t old_ss;
|
sigset_t old_ss;
|
||||||
int pam_code = PAM_SUCCESS, r;
|
int pam_code = PAM_SUCCESS, r;
|
||||||
bool close_session = false;
|
bool close_session = false;
|
||||||
@ -1369,9 +1369,9 @@ static int setup_pam(
|
|||||||
if (log_get_max_level() < LOG_DEBUG)
|
if (log_get_max_level() < LOG_DEBUG)
|
||||||
flags |= PAM_SILENT;
|
flags |= PAM_SILENT;
|
||||||
|
|
||||||
pam_code = sym_pam_start(context->pam_name, user, &conv, &handle);
|
pam_code = sym_pam_start(context->pam_name, user, &conv, &pamh);
|
||||||
if (pam_code != PAM_SUCCESS) {
|
if (pam_code != PAM_SUCCESS) {
|
||||||
handle = NULL;
|
pamh = NULL;
|
||||||
goto fail;
|
goto fail;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1379,32 +1379,32 @@ static int setup_pam(
|
|||||||
if (r < 0)
|
if (r < 0)
|
||||||
goto fail;
|
goto fail;
|
||||||
if (r > 0) {
|
if (r > 0) {
|
||||||
pam_code = sym_pam_set_item(handle, PAM_TTY, tty);
|
pam_code = sym_pam_set_item(pamh, PAM_TTY, tty);
|
||||||
if (pam_code != PAM_SUCCESS)
|
if (pam_code != PAM_SUCCESS)
|
||||||
goto fail;
|
goto fail;
|
||||||
}
|
}
|
||||||
|
|
||||||
STRV_FOREACH(nv, *env) {
|
STRV_FOREACH(nv, *env) {
|
||||||
pam_code = sym_pam_putenv(handle, *nv);
|
pam_code = sym_pam_putenv(pamh, *nv);
|
||||||
if (pam_code != PAM_SUCCESS)
|
if (pam_code != PAM_SUCCESS)
|
||||||
goto fail;
|
goto fail;
|
||||||
}
|
}
|
||||||
|
|
||||||
pam_code = sym_pam_acct_mgmt(handle, flags);
|
pam_code = sym_pam_acct_mgmt(pamh, flags);
|
||||||
if (pam_code != PAM_SUCCESS)
|
if (pam_code != PAM_SUCCESS)
|
||||||
goto fail;
|
goto fail;
|
||||||
|
|
||||||
pam_code = sym_pam_setcred(handle, PAM_ESTABLISH_CRED | flags);
|
pam_code = sym_pam_setcred(pamh, PAM_ESTABLISH_CRED | flags);
|
||||||
if (pam_code != PAM_SUCCESS)
|
if (pam_code != PAM_SUCCESS)
|
||||||
pam_syslog_pam_error(handle, LOG_DEBUG, pam_code, "pam_setcred(PAM_ESTABLISH_CRED) failed, ignoring: @PAMERR@");
|
pam_syslog_pam_error(pamh, LOG_DEBUG, pam_code, "pam_setcred(PAM_ESTABLISH_CRED) failed, ignoring: @PAMERR@");
|
||||||
|
|
||||||
pam_code = sym_pam_open_session(handle, flags);
|
pam_code = sym_pam_open_session(pamh, flags);
|
||||||
if (pam_code != PAM_SUCCESS)
|
if (pam_code != PAM_SUCCESS)
|
||||||
goto fail;
|
goto fail;
|
||||||
|
|
||||||
close_session = true;
|
close_session = true;
|
||||||
|
|
||||||
e = sym_pam_getenvlist(handle);
|
e = sym_pam_getenvlist(pamh);
|
||||||
if (!e) {
|
if (!e) {
|
||||||
pam_code = PAM_BUF_ERR;
|
pam_code = PAM_BUF_ERR;
|
||||||
goto fail;
|
goto fail;
|
||||||
@ -1479,7 +1479,7 @@ static int setup_pam(
|
|||||||
|
|
||||||
/* If our parent died we'll end the session */
|
/* If our parent died we'll end the session */
|
||||||
if (getppid() != parent_pid) {
|
if (getppid() != parent_pid) {
|
||||||
pam_code = pam_close_session_and_delete_credentials(handle, flags);
|
pam_code = pam_close_session_and_delete_credentials(pamh, flags);
|
||||||
if (pam_code != PAM_SUCCESS)
|
if (pam_code != PAM_SUCCESS)
|
||||||
goto child_finish;
|
goto child_finish;
|
||||||
}
|
}
|
||||||
@ -1489,7 +1489,7 @@ static int setup_pam(
|
|||||||
child_finish:
|
child_finish:
|
||||||
/* NB: pam_end() when called in child processes should set PAM_DATA_SILENT to let the module
|
/* NB: pam_end() when called in child processes should set PAM_DATA_SILENT to let the module
|
||||||
* know about this. See pam_end(3) */
|
* know about this. See pam_end(3) */
|
||||||
(void) sym_pam_end(handle, pam_code | flags | PAM_DATA_SILENT);
|
(void) sym_pam_end(pamh, pam_code | flags | PAM_DATA_SILENT);
|
||||||
_exit(ret);
|
_exit(ret);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1497,7 +1497,7 @@ static int setup_pam(
|
|||||||
|
|
||||||
/* If the child was forked off successfully it will do all the cleanups, so forget about the handle
|
/* If the child was forked off successfully it will do all the cleanups, so forget about the handle
|
||||||
* here. */
|
* here. */
|
||||||
handle = NULL;
|
pamh = NULL;
|
||||||
|
|
||||||
/* Unblock SIGTERM again in the parent */
|
/* Unblock SIGTERM again in the parent */
|
||||||
assert_se(sigprocmask(SIG_SETMASK, &old_ss, NULL) >= 0);
|
assert_se(sigprocmask(SIG_SETMASK, &old_ss, NULL) >= 0);
|
||||||
@ -1515,16 +1515,16 @@ static int setup_pam(
|
|||||||
|
|
||||||
fail:
|
fail:
|
||||||
if (pam_code != PAM_SUCCESS) {
|
if (pam_code != PAM_SUCCESS) {
|
||||||
pam_syslog_pam_error(handle, LOG_ERR, pam_code, "PAM failed: @PAMERR@");
|
pam_syslog_pam_error(pamh, LOG_ERR, pam_code, "PAM failed: @PAMERR@");
|
||||||
r = -EPERM; /* PAM errors do not map to errno */
|
r = -EPERM; /* PAM errors do not map to errno */
|
||||||
} else
|
} else
|
||||||
log_error_errno(r, "PAM failed: %m");
|
log_error_errno(r, "PAM failed: %m");
|
||||||
|
|
||||||
if (handle) {
|
if (pamh) {
|
||||||
if (close_session)
|
if (close_session)
|
||||||
pam_code = pam_close_session_and_delete_credentials(handle, flags);
|
pam_code = pam_close_session_and_delete_credentials(pamh, flags);
|
||||||
|
|
||||||
(void) sym_pam_end(handle, pam_code | flags);
|
(void) sym_pam_end(pamh, pam_code | flags);
|
||||||
}
|
}
|
||||||
|
|
||||||
closelog();
|
closelog();
|
||||||
|
|||||||
@ -6,6 +6,5 @@ executables += [
|
|||||||
'public' : true,
|
'public' : true,
|
||||||
'conditions' : ['ENABLE_FIRSTBOOT'],
|
'conditions' : ['ENABLE_FIRSTBOOT'],
|
||||||
'sources' : files('firstboot.c'),
|
'sources' : files('firstboot.c'),
|
||||||
'dependencies' : libcrypt,
|
|
||||||
},
|
},
|
||||||
]
|
]
|
||||||
|
|||||||
@ -64,7 +64,6 @@ executables += [
|
|||||||
'sources' : systemd_homed_sources,
|
'sources' : systemd_homed_sources,
|
||||||
'extract' : systemd_homed_extract_sources,
|
'extract' : systemd_homed_extract_sources,
|
||||||
'dependencies' : [
|
'dependencies' : [
|
||||||
libcrypt,
|
|
||||||
libm,
|
libm,
|
||||||
libopenssl,
|
libopenssl,
|
||||||
threads,
|
threads,
|
||||||
@ -80,7 +79,6 @@ executables += [
|
|||||||
],
|
],
|
||||||
'dependencies' : [
|
'dependencies' : [
|
||||||
libblkid_cflags,
|
libblkid_cflags,
|
||||||
libcrypt,
|
|
||||||
libfdisk,
|
libfdisk,
|
||||||
libopenssl,
|
libopenssl,
|
||||||
libp11kit_cflags,
|
libp11kit_cflags,
|
||||||
@ -93,7 +91,6 @@ executables += [
|
|||||||
'sources' : homectl_sources,
|
'sources' : homectl_sources,
|
||||||
'objects' : ['systemd-homed'],
|
'objects' : ['systemd-homed'],
|
||||||
'dependencies' : [
|
'dependencies' : [
|
||||||
libcrypt,
|
|
||||||
libdl,
|
libdl,
|
||||||
libopenssl,
|
libopenssl,
|
||||||
libp11kit_cflags,
|
libp11kit_cflags,
|
||||||
@ -112,7 +109,6 @@ modules += [
|
|||||||
'conditions' : ['HAVE_PAM'],
|
'conditions' : ['HAVE_PAM'],
|
||||||
'sources' : pam_systemd_home_sources,
|
'sources' : pam_systemd_home_sources,
|
||||||
'dependencies' : [
|
'dependencies' : [
|
||||||
libcrypt,
|
|
||||||
libintl,
|
libintl,
|
||||||
libpam_misc,
|
libpam_misc,
|
||||||
libpam,
|
libpam,
|
||||||
|
|||||||
File diff suppressed because it is too large
Load Diff
13
src/include/musl/crypt.h
Normal file
13
src/include/musl/crypt.h
Normal file
@ -0,0 +1,13 @@
|
|||||||
|
/* SPDX-License-Identifier: LGPL-2.1-or-later */
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include_next <crypt.h>
|
||||||
|
|
||||||
|
const char* missing_crypt_preferred_method(void);
|
||||||
|
#define crypt_preferred_method missing_crypt_preferred_method
|
||||||
|
|
||||||
|
char* missing_crypt_gensalt_ra(const char *prefix, unsigned long count, const char *rbytes, int nrbytes);
|
||||||
|
#define crypt_gensalt_ra missing_crypt_gensalt_ra
|
||||||
|
|
||||||
|
char* missing_crypt_ra(const char *phrase, const char *setting, void **data, int *size);
|
||||||
|
#define crypt_ra missing_crypt_ra
|
||||||
111
src/libc/musl/crypt.c
Normal file
111
src/libc/musl/crypt.c
Normal file
@ -0,0 +1,111 @@
|
|||||||
|
/* SPDX-License-Identifier: LGPL-2.1-or-later */
|
||||||
|
|
||||||
|
#include <assert.h>
|
||||||
|
#include <crypt.h>
|
||||||
|
#include <errno.h>
|
||||||
|
#include <stdbool.h>
|
||||||
|
#include <stdint.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <string.h>
|
||||||
|
#include <sys/random.h>
|
||||||
|
|
||||||
|
const char* missing_crypt_preferred_method(void) {
|
||||||
|
return "$6$";
|
||||||
|
}
|
||||||
|
|
||||||
|
char* missing_crypt_gensalt_ra(const char *prefix, unsigned long count, const char *rbytes, int nrbytes) {
|
||||||
|
static const char table[] =
|
||||||
|
"abcdefghijklmnopqrstuvwxyz"
|
||||||
|
"ABCDEFGHIJKLMNOPQRSTUVWXYZ"
|
||||||
|
"0123456789"
|
||||||
|
"./";
|
||||||
|
|
||||||
|
static_assert(sizeof(table) == 64U + 1U);
|
||||||
|
|
||||||
|
/* This doesn't do anything but SHA512, and silently ignore all arguments, to make it legacy-free and
|
||||||
|
* minimize the implementation. */
|
||||||
|
|
||||||
|
/* Insist on the best randomness by getrandom(), this is about keeping passwords secret after all. */
|
||||||
|
uint8_t raw[16];
|
||||||
|
for (size_t i = 0; i < sizeof(raw);) {
|
||||||
|
size_t n = sizeof(raw) - i;
|
||||||
|
ssize_t l = getrandom(raw + i, n, 0);
|
||||||
|
if (l < 0)
|
||||||
|
return NULL;
|
||||||
|
if (l == 0) {
|
||||||
|
/* Weird, should never happen. */
|
||||||
|
errno = EIO;
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
if ((size_t) l == n)
|
||||||
|
break; /* Done reading, success. */
|
||||||
|
|
||||||
|
i += l;
|
||||||
|
/* Interrupted by a signal; keep going. */
|
||||||
|
}
|
||||||
|
|
||||||
|
/* "$6$" + salt + "$" + NUL */
|
||||||
|
char *salt = malloc(3 + sizeof(raw) + 1 + 1);
|
||||||
|
if (!salt) {
|
||||||
|
errno = ENOMEM;
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* We only bother with SHA512 hashed passwords, the rest is legacy, and we don't do legacy. */
|
||||||
|
char *p = stpcpy(salt, "$6$");
|
||||||
|
for (size_t i = 0; i < sizeof(raw); i++)
|
||||||
|
*p++ = table[raw[i] & 63];
|
||||||
|
*p++ = '$';
|
||||||
|
*p = '\0';
|
||||||
|
|
||||||
|
return salt;
|
||||||
|
}
|
||||||
|
|
||||||
|
char* missing_crypt_ra(const char *phrase, const char *setting, void **data, int *size) {
|
||||||
|
struct crypt_data *buf = NULL;
|
||||||
|
bool allocated = false;
|
||||||
|
|
||||||
|
if (!phrase || !setting || !data || !size) {
|
||||||
|
errno = EINVAL;
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (*data) {
|
||||||
|
if (*size != sizeof(struct crypt_data)) {
|
||||||
|
errno = EINVAL;
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
buf = *data;
|
||||||
|
} else {
|
||||||
|
if (*size != 0) {
|
||||||
|
errno = EINVAL;
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
buf = calloc(1, sizeof(struct crypt_data));
|
||||||
|
if (!buf) {
|
||||||
|
errno = ENOMEM;
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
allocated = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* crypt_r may return a pointer to an invalid hashed password on error. Our callers expect NULL on
|
||||||
|
* error, so let's just return that. */
|
||||||
|
|
||||||
|
char *t = crypt_r(phrase, setting, buf);
|
||||||
|
if (!t || t[0] == '*') {
|
||||||
|
if (allocated)
|
||||||
|
free(buf);
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (allocated) {
|
||||||
|
*data = buf;
|
||||||
|
*size = sizeof(struct crypt_data);
|
||||||
|
}
|
||||||
|
return t;
|
||||||
|
}
|
||||||
@ -5,6 +5,7 @@ if get_option('libc') != 'musl'
|
|||||||
endif
|
endif
|
||||||
|
|
||||||
libc_wrapper_sources += files(
|
libc_wrapper_sources += files(
|
||||||
|
'crypt.c',
|
||||||
'getopt.c',
|
'getopt.c',
|
||||||
'printf.c',
|
'printf.c',
|
||||||
'stdio.c',
|
'stdio.c',
|
||||||
|
|||||||
File diff suppressed because it is too large
Load Diff
@ -11,13 +11,13 @@
|
|||||||
static const char DEFAULT_KEYNAME[] = "cryptsetup";
|
static const char DEFAULT_KEYNAME[] = "cryptsetup";
|
||||||
|
|
||||||
_public_ PAM_EXTERN int pam_sm_authenticate(
|
_public_ PAM_EXTERN int pam_sm_authenticate(
|
||||||
pam_handle_t *handle,
|
pam_handle_t *pamh,
|
||||||
int flags,
|
int flags,
|
||||||
int argc, const char **argv) {
|
int argc, const char **argv) {
|
||||||
|
|
||||||
int r;
|
int r;
|
||||||
|
|
||||||
assert(handle);
|
assert(pamh);
|
||||||
|
|
||||||
r = dlopen_libpam();
|
r = dlopen_libpam();
|
||||||
if (r < 0)
|
if (r < 0)
|
||||||
@ -41,10 +41,10 @@ _public_ PAM_EXTERN int pam_sm_authenticate(
|
|||||||
else if (streq(argv[i], "debug"))
|
else if (streq(argv[i], "debug"))
|
||||||
debug = true;
|
debug = true;
|
||||||
else
|
else
|
||||||
pam_syslog(handle, LOG_WARNING, "Unknown parameter '%s', ignoring.", argv[i]);
|
pam_syslog(pamh, LOG_WARNING, "Unknown parameter '%s', ignoring.", argv[i]);
|
||||||
}
|
}
|
||||||
|
|
||||||
pam_debug_syslog(handle, debug, "pam-systemd-loadkey: initializing...");
|
pam_debug_syslog(pamh, debug, "pam-systemd-loadkey: initializing...");
|
||||||
|
|
||||||
/* Retrieve the key. */
|
/* Retrieve the key. */
|
||||||
|
|
||||||
@ -52,13 +52,13 @@ _public_ PAM_EXTERN int pam_sm_authenticate(
|
|||||||
serial = request_key("user", keyname, NULL, 0);
|
serial = request_key("user", keyname, NULL, 0);
|
||||||
if (serial < 0) {
|
if (serial < 0) {
|
||||||
if (errno == ENOKEY) {
|
if (errno == ENOKEY) {
|
||||||
pam_debug_syslog(handle, debug, "Key not found: %s", keyname);
|
pam_debug_syslog(pamh, debug, "Key not found: %s", keyname);
|
||||||
return PAM_AUTHINFO_UNAVAIL;
|
return PAM_AUTHINFO_UNAVAIL;
|
||||||
} else if (errno == EKEYEXPIRED) {
|
} else if (errno == EKEYEXPIRED) {
|
||||||
pam_debug_syslog(handle, debug, "Key expired: %s", keyname);
|
pam_debug_syslog(pamh, debug, "Key expired: %s", keyname);
|
||||||
return PAM_AUTHINFO_UNAVAIL;
|
return PAM_AUTHINFO_UNAVAIL;
|
||||||
} else
|
} else
|
||||||
return pam_syslog_errno(handle, LOG_ERR, errno, "Failed to look up the key: %m");
|
return pam_syslog_errno(pamh, LOG_ERR, errno, "Failed to look up the key: %m");
|
||||||
}
|
}
|
||||||
|
|
||||||
_cleanup_(erase_and_freep) void *p = NULL;
|
_cleanup_(erase_and_freep) void *p = NULL;
|
||||||
@ -66,30 +66,30 @@ _public_ PAM_EXTERN int pam_sm_authenticate(
|
|||||||
|
|
||||||
r = keyring_read(serial, &p, &n);
|
r = keyring_read(serial, &p, &n);
|
||||||
if (r < 0)
|
if (r < 0)
|
||||||
return pam_syslog_errno(handle, LOG_ERR, r, "Failed to read the key: %m");
|
return pam_syslog_errno(pamh, LOG_ERR, r, "Failed to read the key: %m");
|
||||||
|
|
||||||
/* Split the key by NUL. Set the last item as authtok. */
|
/* Split the key by NUL. Set the last item as authtok. */
|
||||||
|
|
||||||
_cleanup_strv_free_erase_ char **passwords = strv_parse_nulstr(p, n);
|
_cleanup_strv_free_erase_ char **passwords = strv_parse_nulstr(p, n);
|
||||||
if (!passwords)
|
if (!passwords)
|
||||||
return pam_log_oom(handle);
|
return pam_log_oom(pamh);
|
||||||
|
|
||||||
size_t passwords_len = strv_length(passwords);
|
size_t passwords_len = strv_length(passwords);
|
||||||
if (passwords_len == 0) {
|
if (passwords_len == 0) {
|
||||||
pam_debug_syslog(handle, debug, "Key is empty.");
|
pam_debug_syslog(pamh, debug, "Key is empty.");
|
||||||
return PAM_AUTHINFO_UNAVAIL;
|
return PAM_AUTHINFO_UNAVAIL;
|
||||||
} else if (passwords_len > 1)
|
} else if (passwords_len > 1)
|
||||||
pam_debug_syslog(handle, debug, "Multiple passwords found in the key. Using the last one.");
|
pam_debug_syslog(pamh, debug, "Multiple passwords found in the key. Using the last one.");
|
||||||
|
|
||||||
r = pam_set_item(handle, PAM_AUTHTOK, passwords[passwords_len - 1]);
|
r = pam_set_item(pamh, PAM_AUTHTOK, passwords[passwords_len - 1]);
|
||||||
if (r != PAM_SUCCESS)
|
if (r != PAM_SUCCESS)
|
||||||
return pam_syslog_pam_error(handle, LOG_ERR, r, "Failed to set PAM auth token: @PAMERR@");
|
return pam_syslog_pam_error(pamh, LOG_ERR, r, "Failed to set PAM auth token: @PAMERR@");
|
||||||
|
|
||||||
return PAM_SUCCESS;
|
return PAM_SUCCESS;
|
||||||
}
|
}
|
||||||
|
|
||||||
_public_ PAM_EXTERN int pam_sm_setcred(
|
_public_ PAM_EXTERN int pam_sm_setcred(
|
||||||
pam_handle_t *handle,
|
pam_handle_t *pamh,
|
||||||
int flags,
|
int flags,
|
||||||
int argc, const char **argv) {
|
int argc, const char **argv) {
|
||||||
|
|
||||||
|
|||||||
@ -1,145 +1,160 @@
|
|||||||
/* SPDX-License-Identifier: LGPL-2.1-or-later */
|
/* SPDX-License-Identifier: LGPL-2.1-or-later */
|
||||||
|
|
||||||
#include <crypt.h>
|
#if HAVE_LIBCRYPT
|
||||||
#include <stdlib.h>
|
# include <crypt.h>
|
||||||
|
#endif
|
||||||
|
|
||||||
#include "alloc-util.h"
|
#include "alloc-util.h"
|
||||||
|
#include "dlfcn-util.h"
|
||||||
#include "errno-util.h"
|
#include "errno-util.h"
|
||||||
#include "libcrypt-util.h"
|
#include "libcrypt-util.h"
|
||||||
#include "log.h"
|
#include "log.h"
|
||||||
#include "random-util.h" /* IWYU pragma: keep */
|
|
||||||
#include "string-util.h"
|
#include "string-util.h"
|
||||||
#include "strv.h"
|
#include "strv.h"
|
||||||
|
|
||||||
int make_salt(char **ret) {
|
#if HAVE_LIBCRYPT
|
||||||
|
static void *libcrypt_dl = NULL;
|
||||||
|
|
||||||
#if HAVE_CRYPT_GENSALT_RA
|
static DLSYM_PROTOTYPE(crypt_gensalt_ra) = NULL;
|
||||||
|
static DLSYM_PROTOTYPE(crypt_preferred_method) = NULL;
|
||||||
|
static DLSYM_PROTOTYPE(crypt_ra) = NULL;
|
||||||
|
|
||||||
|
int dlopen_libcrypt(void) {
|
||||||
|
#ifdef __GLIBC__
|
||||||
|
static int cached = 0;
|
||||||
|
int r;
|
||||||
|
|
||||||
|
if (libcrypt_dl)
|
||||||
|
return 0; /* Already loaded */
|
||||||
|
|
||||||
|
if (cached < 0)
|
||||||
|
return cached; /* Already tried, and failed. */
|
||||||
|
|
||||||
|
/* Several distributions like Debian/Ubuntu and OpenSUSE provide libxcrypt as libcrypt.so.1,
|
||||||
|
* while others like Fedora/CentOS and Arch provide it as libcrypt.so.2. */
|
||||||
|
ELF_NOTE_DLOPEN("crypt",
|
||||||
|
"Support for hashing passwords",
|
||||||
|
ELF_NOTE_DLOPEN_PRIORITY_RECOMMENDED,
|
||||||
|
"libcrypt.so.2", "libcrypt.so.1");
|
||||||
|
|
||||||
|
_cleanup_(dlclosep) void *dl = NULL;
|
||||||
|
r = dlopen_safe("libcrypt.so.2", &dl, /* reterr_dlerror= */ NULL);
|
||||||
|
if (r < 0) {
|
||||||
|
const char *dle = NULL;
|
||||||
|
r = dlopen_safe("libcrypt.so.1", &dl, &dle);
|
||||||
|
if (r < 0) {
|
||||||
|
log_debug_errno(r, "libcrypt.so.2/libcrypt.so.1 is not available: %s", dle ?: STRERROR(r));
|
||||||
|
return (cached = -EOPNOTSUPP); /* turn into recognizable error */
|
||||||
|
}
|
||||||
|
log_debug("Loaded 'libcrypt.so.1' via dlopen()");
|
||||||
|
} else
|
||||||
|
log_debug("Loaded 'libcrypt.so.2' via dlopen()");
|
||||||
|
|
||||||
|
r = dlsym_many_or_warn(
|
||||||
|
dl, LOG_DEBUG,
|
||||||
|
DLSYM_ARG(crypt_gensalt_ra),
|
||||||
|
DLSYM_ARG(crypt_preferred_method),
|
||||||
|
DLSYM_ARG(crypt_ra));
|
||||||
|
if (r < 0)
|
||||||
|
return (cached = r);
|
||||||
|
|
||||||
|
libcrypt_dl = TAKE_PTR(dl);
|
||||||
|
#else
|
||||||
|
libcrypt_dl = NULL;
|
||||||
|
sym_crypt_gensalt_ra = missing_crypt_gensalt_ra;
|
||||||
|
sym_crypt_preferred_method = missing_crypt_preferred_method;
|
||||||
|
sym_crypt_ra = missing_crypt_ra;
|
||||||
|
#endif
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
int make_salt(char **ret) {
|
||||||
const char *e;
|
const char *e;
|
||||||
char *salt;
|
char *salt;
|
||||||
|
int r;
|
||||||
|
|
||||||
/* If we have crypt_gensalt_ra() we default to the "preferred method" (i.e. usually yescrypt).
|
assert(ret);
|
||||||
* crypt_gensalt_ra() is usually provided by libxcrypt. */
|
|
||||||
|
r = dlopen_libcrypt();
|
||||||
|
if (r < 0)
|
||||||
|
return r;
|
||||||
|
|
||||||
e = secure_getenv("SYSTEMD_CRYPT_PREFIX");
|
e = secure_getenv("SYSTEMD_CRYPT_PREFIX");
|
||||||
if (!e)
|
if (!e)
|
||||||
#if HAVE_CRYPT_PREFERRED_METHOD
|
e = sym_crypt_preferred_method();
|
||||||
e = crypt_preferred_method();
|
|
||||||
#else
|
|
||||||
e = "$6$";
|
|
||||||
#endif
|
|
||||||
|
|
||||||
log_debug("Generating salt for hash prefix: %s", e);
|
log_debug("Generating salt for hash prefix: %s", e);
|
||||||
|
|
||||||
salt = crypt_gensalt_ra(e, 0, NULL, 0);
|
salt = sym_crypt_gensalt_ra(e, 0, NULL, 0);
|
||||||
if (!salt)
|
if (!salt)
|
||||||
return -errno;
|
return -errno;
|
||||||
|
|
||||||
*ret = salt;
|
*ret = salt;
|
||||||
return 0;
|
return 0;
|
||||||
#else
|
|
||||||
/* If crypt_gensalt_ra() is not available, we use SHA512 and generate the salt on our own. */
|
|
||||||
|
|
||||||
static const char table[] =
|
|
||||||
"abcdefghijklmnopqrstuvwxyz"
|
|
||||||
"ABCDEFGHIJKLMNOPQRSTUVWXYZ"
|
|
||||||
"0123456789"
|
|
||||||
"./";
|
|
||||||
|
|
||||||
uint8_t raw[16];
|
|
||||||
char *salt, *j;
|
|
||||||
size_t i;
|
|
||||||
int r;
|
|
||||||
|
|
||||||
/* This is a bit like crypt_gensalt_ra(), but doesn't require libcrypt, and doesn't do anything but
|
|
||||||
* SHA512, i.e. is legacy-free and minimizes our deps. */
|
|
||||||
|
|
||||||
assert_cc(sizeof(table) == 64U + 1U);
|
|
||||||
|
|
||||||
log_debug("Generating fallback salt for hash prefix: $6$");
|
|
||||||
|
|
||||||
/* Insist on the best randomness by setting RANDOM_BLOCK, this is about keeping passwords secret after all. */
|
|
||||||
r = crypto_random_bytes(raw, sizeof(raw));
|
|
||||||
if (r < 0)
|
|
||||||
return r;
|
|
||||||
|
|
||||||
salt = new(char, 3+sizeof(raw)+1+1);
|
|
||||||
if (!salt)
|
|
||||||
return -ENOMEM;
|
|
||||||
|
|
||||||
/* We only bother with SHA512 hashed passwords, the rest is legacy, and we don't do legacy. */
|
|
||||||
j = stpcpy(salt, "$6$");
|
|
||||||
for (i = 0; i < sizeof(raw); i++)
|
|
||||||
j[i] = table[raw[i] & 63];
|
|
||||||
j[i++] = '$';
|
|
||||||
j[i] = 0;
|
|
||||||
|
|
||||||
*ret = salt;
|
|
||||||
return 0;
|
|
||||||
#endif
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#if HAVE_CRYPT_RA
|
int hash_password(const char *password, char **ret) {
|
||||||
# define CRYPT_RA_NAME "crypt_ra"
|
|
||||||
#else
|
|
||||||
# define CRYPT_RA_NAME "crypt_r"
|
|
||||||
|
|
||||||
/* Provide a poor man's fallback that uses a fixed size buffer. */
|
|
||||||
|
|
||||||
static char* systemd_crypt_ra(const char *phrase, const char *setting, void **data, int *size) {
|
|
||||||
assert(data);
|
|
||||||
assert(size);
|
|
||||||
|
|
||||||
/* We allocate the buffer because crypt(3) says: struct crypt_data may be quite large (32kB in this
|
|
||||||
* implementation of libcrypt; over 128kB in some other implementations). This is large enough that
|
|
||||||
* it may be unwise to allocate it on the stack. */
|
|
||||||
|
|
||||||
if (!*data) {
|
|
||||||
*data = new0(struct crypt_data, 1);
|
|
||||||
if (!*data) {
|
|
||||||
errno = ENOMEM;
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
*size = (int) (sizeof(struct crypt_data));
|
|
||||||
}
|
|
||||||
|
|
||||||
char *t = crypt_r(phrase, setting, *data);
|
|
||||||
if (!t)
|
|
||||||
return NULL;
|
|
||||||
|
|
||||||
/* crypt_r may return a pointer to an invalid hashed password on error. Our callers expect NULL on
|
|
||||||
* error, so let's just return that. */
|
|
||||||
if (t[0] == '*')
|
|
||||||
return NULL;
|
|
||||||
|
|
||||||
return t;
|
|
||||||
}
|
|
||||||
|
|
||||||
#define crypt_ra systemd_crypt_ra
|
|
||||||
|
|
||||||
#endif
|
|
||||||
|
|
||||||
int hash_password_full(const char *password, void **cd_data, int *cd_size, char **ret) {
|
|
||||||
_cleanup_free_ char *salt = NULL;
|
_cleanup_free_ char *salt = NULL;
|
||||||
_cleanup_(erase_and_freep) void *_cd_data = NULL;
|
_cleanup_(erase_and_freep) void *cd_data = NULL;
|
||||||
const char *p;
|
const char *p;
|
||||||
int r, _cd_size = 0;
|
int r, cd_size = 0;
|
||||||
|
|
||||||
assert(!!cd_data == !!cd_size);
|
assert(password);
|
||||||
|
assert(ret);
|
||||||
|
|
||||||
r = make_salt(&salt);
|
r = make_salt(&salt);
|
||||||
if (r < 0)
|
if (r < 0)
|
||||||
return log_debug_errno(r, "Failed to generate salt: %m");
|
return log_debug_errno(r, "Failed to generate salt: %m");
|
||||||
|
|
||||||
errno = 0;
|
errno = 0;
|
||||||
p = crypt_ra(password, salt, cd_data ?: &_cd_data, cd_size ?: &_cd_size);
|
p = sym_crypt_ra(password, salt, &cd_data, &cd_size);
|
||||||
if (!p)
|
if (!p)
|
||||||
return log_debug_errno(errno_or_else(SYNTHETIC_ERRNO(EINVAL)),
|
return log_debug_errno(errno_or_else(SYNTHETIC_ERRNO(EINVAL)), "crypt_ra() failed: %m");
|
||||||
CRYPT_RA_NAME "() failed: %m");
|
|
||||||
|
|
||||||
return strdup_to(ret, p);
|
return strdup_to(ret, p);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
int test_password_one(const char *hashed_password, const char *password) {
|
||||||
|
_cleanup_(erase_and_freep) void *cd_data = NULL;
|
||||||
|
int r, cd_size = 0;
|
||||||
|
const char *k;
|
||||||
|
|
||||||
|
assert(hashed_password);
|
||||||
|
assert(password);
|
||||||
|
|
||||||
|
r = dlopen_libcrypt();
|
||||||
|
if (r < 0)
|
||||||
|
return r;
|
||||||
|
|
||||||
|
errno = 0;
|
||||||
|
k = sym_crypt_ra(password, hashed_password, &cd_data, &cd_size);
|
||||||
|
if (!k) {
|
||||||
|
if (errno == ENOMEM)
|
||||||
|
return -ENOMEM;
|
||||||
|
/* Unknown or unavailable hashing method or string too short */
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
return streq(k, hashed_password);
|
||||||
|
}
|
||||||
|
|
||||||
|
int test_password_many(char **hashed_password, const char *password) {
|
||||||
|
int r;
|
||||||
|
|
||||||
|
assert(password);
|
||||||
|
|
||||||
|
STRV_FOREACH(hpw, hashed_password) {
|
||||||
|
r = test_password_one(*hpw, password);
|
||||||
|
if (r < 0)
|
||||||
|
return r;
|
||||||
|
if (r > 0)
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
bool looks_like_hashed_password(const char *s) {
|
bool looks_like_hashed_password(const char *s) {
|
||||||
/* Returns false if the specified string is certainly not a hashed UNIX password. crypt(5) lists
|
/* 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
|
* various hashing methods. We only reject (return false) strings which are documented to have
|
||||||
@ -155,34 +170,3 @@ bool looks_like_hashed_password(const char *s) {
|
|||||||
|
|
||||||
return !STR_IN_SET(s, "x", "*");
|
return !STR_IN_SET(s, "x", "*");
|
||||||
}
|
}
|
||||||
|
|
||||||
int test_password_one(const char *hashed_password, const char *password) {
|
|
||||||
_cleanup_(erase_and_freep) void *cd_data = NULL;
|
|
||||||
int cd_size = 0;
|
|
||||||
const char *k;
|
|
||||||
|
|
||||||
errno = 0;
|
|
||||||
k = crypt_ra(password, hashed_password, &cd_data, &cd_size);
|
|
||||||
if (!k) {
|
|
||||||
if (errno == ENOMEM)
|
|
||||||
return -ENOMEM;
|
|
||||||
/* Unknown or unavailable hashing method or string too short */
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
return streq(k, hashed_password);
|
|
||||||
}
|
|
||||||
|
|
||||||
int test_password_many(char **hashed_password, const char *password) {
|
|
||||||
int r;
|
|
||||||
|
|
||||||
STRV_FOREACH(hpw, hashed_password) {
|
|
||||||
r = test_password_one(*hpw, password);
|
|
||||||
if (r < 0)
|
|
||||||
return r;
|
|
||||||
if (r > 0)
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|||||||
@ -3,11 +3,21 @@
|
|||||||
|
|
||||||
#include "shared-forward.h"
|
#include "shared-forward.h"
|
||||||
|
|
||||||
|
#if HAVE_LIBCRYPT
|
||||||
|
int dlopen_libcrypt(void);
|
||||||
int make_salt(char **ret);
|
int make_salt(char **ret);
|
||||||
int hash_password_full(const char *password, void **cd_data, int *cd_size, char **ret);
|
int hash_password(const char *password, char **ret);
|
||||||
static inline int hash_password(const char *password, char **ret) {
|
|
||||||
return hash_password_full(password, NULL, NULL, ret);
|
|
||||||
}
|
|
||||||
bool looks_like_hashed_password(const char *s);
|
|
||||||
int test_password_one(const char *hashed_password, const char *password);
|
int test_password_one(const char *hashed_password, const char *password);
|
||||||
int test_password_many(char **hashed_password, const char *password);
|
int test_password_many(char **hashed_password, const char *password);
|
||||||
|
|
||||||
|
#else
|
||||||
|
|
||||||
|
static inline int dlopen_libcrypt(void) {
|
||||||
|
return -EOPNOTSUPP;
|
||||||
|
}
|
||||||
|
static inline int hash_password(const char *password, char **ret) {
|
||||||
|
return -EOPNOTSUPP;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
bool looks_like_hashed_password(const char *s);
|
||||||
|
|||||||
@ -367,7 +367,7 @@ libshared_deps = [threads,
|
|||||||
libaudit_cflags,
|
libaudit_cflags,
|
||||||
libblkid_cflags,
|
libblkid_cflags,
|
||||||
libbpf_cflags,
|
libbpf_cflags,
|
||||||
libcrypt,
|
libcrypt_cflags,
|
||||||
libcryptsetup_cflags,
|
libcryptsetup_cflags,
|
||||||
libdl,
|
libdl,
|
||||||
libdw_cflags,
|
libdw_cflags,
|
||||||
|
|||||||
@ -73,20 +73,20 @@ int errno_to_pam_error(int error) {
|
|||||||
return ERRNO_VALUE(error) == ENOMEM ? PAM_BUF_ERR : PAM_SERVICE_ERR;
|
return ERRNO_VALUE(error) == ENOMEM ? PAM_BUF_ERR : PAM_SERVICE_ERR;
|
||||||
}
|
}
|
||||||
|
|
||||||
int pam_syslog_errno(pam_handle_t *handle, int level, int error, const char *format, ...) {
|
int pam_syslog_errno(pam_handle_t *pamh, int level, int error, const char *format, ...) {
|
||||||
va_list ap;
|
va_list ap;
|
||||||
|
|
||||||
error = ERRNO_VALUE(error);
|
error = ERRNO_VALUE(error);
|
||||||
LOCAL_ERRNO(error);
|
LOCAL_ERRNO(error);
|
||||||
|
|
||||||
va_start(ap, format);
|
va_start(ap, format);
|
||||||
sym_pam_vsyslog(handle, level, format, ap);
|
sym_pam_vsyslog(pamh, level, format, ap);
|
||||||
va_end(ap);
|
va_end(ap);
|
||||||
|
|
||||||
return errno_to_pam_error(error);
|
return errno_to_pam_error(error);
|
||||||
}
|
}
|
||||||
|
|
||||||
int pam_syslog_pam_error(pam_handle_t *handle, int level, int error, const char *format, ...) {
|
int pam_syslog_pam_error(pam_handle_t *pamh, int level, int error, const char *format, ...) {
|
||||||
/* This wraps pam_syslog() but will replace @PAMERR@ with a string from pam_strerror().
|
/* This wraps pam_syslog() but will replace @PAMERR@ with a string from pam_strerror().
|
||||||
* @PAMERR@ must be at the very end. */
|
* @PAMERR@ must be at the very end. */
|
||||||
|
|
||||||
@ -95,7 +95,7 @@ int pam_syslog_pam_error(pam_handle_t *handle, int level, int error, const char
|
|||||||
|
|
||||||
const char *p = endswith(format, "@PAMERR@");
|
const char *p = endswith(format, "@PAMERR@");
|
||||||
if (p) {
|
if (p) {
|
||||||
const char *pamerr = sym_pam_strerror(handle, error);
|
const char *pamerr = sym_pam_strerror(pamh, error);
|
||||||
if (strchr(pamerr, '%'))
|
if (strchr(pamerr, '%'))
|
||||||
pamerr = "n/a"; /* We cannot have any formatting chars */
|
pamerr = "n/a"; /* We cannot have any formatting chars */
|
||||||
|
|
||||||
@ -103,10 +103,10 @@ int pam_syslog_pam_error(pam_handle_t *handle, int level, int error, const char
|
|||||||
xsprintf(buf, "%.*s%s", (int)(p - format), format, pamerr);
|
xsprintf(buf, "%.*s%s", (int)(p - format), format, pamerr);
|
||||||
|
|
||||||
DISABLE_WARNING_FORMAT_NONLITERAL;
|
DISABLE_WARNING_FORMAT_NONLITERAL;
|
||||||
sym_pam_vsyslog(handle, level, buf, ap);
|
sym_pam_vsyslog(pamh, level, buf, ap);
|
||||||
REENABLE_WARNING;
|
REENABLE_WARNING;
|
||||||
} else
|
} else
|
||||||
sym_pam_vsyslog(handle, level, format, ap);
|
sym_pam_vsyslog(pamh, level, format, ap);
|
||||||
|
|
||||||
va_end(ap);
|
va_end(ap);
|
||||||
|
|
||||||
@ -142,7 +142,7 @@ static PamBusData *pam_bus_data_free(PamBusData *d) {
|
|||||||
|
|
||||||
DEFINE_TRIVIAL_CLEANUP_FUNC(PamBusData*, pam_bus_data_free);
|
DEFINE_TRIVIAL_CLEANUP_FUNC(PamBusData*, pam_bus_data_free);
|
||||||
|
|
||||||
static void pam_bus_data_destroy(pam_handle_t *handle, void *data, int error_status) {
|
static void pam_bus_data_destroy(pam_handle_t *pamh, void *data, int error_status) {
|
||||||
/* Destructor when called from PAM. Note that error_status is supposed to tell us via PAM_DATA_SILENT
|
/* Destructor when called from PAM. Note that error_status is supposed to tell us via PAM_DATA_SILENT
|
||||||
* whether we are called in a forked off child of the PAM session or in the original parent. We don't
|
* whether we are called in a forked off child of the PAM session or in the original parent. We don't
|
||||||
* bother with that however, and instead rely on the PID checks that sd_bus_flush_close_unref() does
|
* bother with that however, and instead rely on the PID checks that sd_bus_flush_close_unref() does
|
||||||
@ -156,7 +156,7 @@ static void pam_bus_data_destroy(pam_handle_t *handle, void *data, int error_sta
|
|||||||
if (FLAGS_SET(error_status, PAM_DATA_SILENT) &&
|
if (FLAGS_SET(error_status, PAM_DATA_SILENT) &&
|
||||||
d->bus && bus_origin_changed(d->bus))
|
d->bus && bus_origin_changed(d->bus))
|
||||||
/* Please adjust test/units/end.sh when updating the log message. */
|
/* Please adjust test/units/end.sh when updating the log message. */
|
||||||
sym_pam_syslog(handle, LOG_DEBUG,
|
sym_pam_syslog(pamh, LOG_DEBUG,
|
||||||
"Warning: cannot close sd-bus connection (%s) after fork when it was opened before the fork.",
|
"Warning: cannot close sd-bus connection (%s) after fork when it was opened before the fork.",
|
||||||
strna(d->cache_id));
|
strna(d->cache_id));
|
||||||
|
|
||||||
@ -180,7 +180,7 @@ static char* pam_make_bus_cache_id(const char *module_name) {
|
|||||||
|
|
||||||
void pam_bus_data_disconnectp(PamBusData **_d) {
|
void pam_bus_data_disconnectp(PamBusData **_d) {
|
||||||
PamBusData *d = *ASSERT_PTR(_d);
|
PamBusData *d = *ASSERT_PTR(_d);
|
||||||
pam_handle_t *handle;
|
pam_handle_t *pamh;
|
||||||
int r;
|
int r;
|
||||||
|
|
||||||
/* Disconnects the connection explicitly (for use via _cleanup_()) when called */
|
/* Disconnects the connection explicitly (for use via _cleanup_()) when called */
|
||||||
@ -188,17 +188,17 @@ void pam_bus_data_disconnectp(PamBusData **_d) {
|
|||||||
if (!d)
|
if (!d)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
handle = ASSERT_PTR(d->pam_handle); /* Keep a reference to the session even after 'd' might be invalidated */
|
pamh = ASSERT_PTR(d->pam_handle); /* Keep a reference to the session even after 'd' might be invalidated */
|
||||||
|
|
||||||
r = sym_pam_set_data(handle, ASSERT_PTR(d->cache_id), NULL, NULL);
|
r = sym_pam_set_data(pamh, ASSERT_PTR(d->cache_id), NULL, NULL);
|
||||||
if (r != PAM_SUCCESS)
|
if (r != PAM_SUCCESS)
|
||||||
pam_syslog_pam_error(handle, LOG_ERR, r, "Failed to release PAM user record data, ignoring: @PAMERR@");
|
pam_syslog_pam_error(pamh, LOG_ERR, r, "Failed to release PAM user record data, ignoring: @PAMERR@");
|
||||||
|
|
||||||
/* Note, the pam_set_data() call will invalidate 'd', don't access here anymore */
|
/* Note, the pam_set_data() call will invalidate 'd', don't access here anymore */
|
||||||
}
|
}
|
||||||
|
|
||||||
int pam_acquire_bus_connection(
|
int pam_acquire_bus_connection(
|
||||||
pam_handle_t *handle,
|
pam_handle_t *pamh,
|
||||||
const char *module_name,
|
const char *module_name,
|
||||||
bool debug,
|
bool debug,
|
||||||
sd_bus **ret_bus,
|
sd_bus **ret_bus,
|
||||||
@ -208,39 +208,39 @@ int pam_acquire_bus_connection(
|
|||||||
_cleanup_free_ char *cache_id = NULL;
|
_cleanup_free_ char *cache_id = NULL;
|
||||||
int r;
|
int r;
|
||||||
|
|
||||||
assert(handle);
|
assert(pamh);
|
||||||
assert(module_name);
|
assert(module_name);
|
||||||
assert(ret_bus);
|
assert(ret_bus);
|
||||||
|
|
||||||
cache_id = pam_make_bus_cache_id(module_name);
|
cache_id = pam_make_bus_cache_id(module_name);
|
||||||
if (!cache_id)
|
if (!cache_id)
|
||||||
return pam_log_oom(handle);
|
return pam_log_oom(pamh);
|
||||||
|
|
||||||
/* We cache the bus connection so that we can share it between the session and the authentication hooks */
|
/* We cache the bus connection so that we can share it between the session and the authentication hooks */
|
||||||
r = sym_pam_get_data(handle, cache_id, (const void**) &d);
|
r = sym_pam_get_data(pamh, cache_id, (const void**) &d);
|
||||||
if (r == PAM_SUCCESS && d)
|
if (r == PAM_SUCCESS && d)
|
||||||
goto success;
|
goto success;
|
||||||
if (!IN_SET(r, PAM_SUCCESS, PAM_NO_MODULE_DATA))
|
if (!IN_SET(r, PAM_SUCCESS, PAM_NO_MODULE_DATA))
|
||||||
return pam_syslog_pam_error(handle, LOG_ERR, r, "Failed to get bus connection: @PAMERR@");
|
return pam_syslog_pam_error(pamh, LOG_ERR, r, "Failed to get bus connection: @PAMERR@");
|
||||||
|
|
||||||
d = new(PamBusData, 1);
|
d = new(PamBusData, 1);
|
||||||
if (!d)
|
if (!d)
|
||||||
return pam_log_oom(handle);
|
return pam_log_oom(pamh);
|
||||||
|
|
||||||
*d = (PamBusData) {
|
*d = (PamBusData) {
|
||||||
.cache_id = TAKE_PTR(cache_id),
|
.cache_id = TAKE_PTR(cache_id),
|
||||||
.pam_handle = handle,
|
.pam_handle = pamh,
|
||||||
};
|
};
|
||||||
|
|
||||||
r = sd_bus_open_system(&d->bus);
|
r = sd_bus_open_system(&d->bus);
|
||||||
if (r < 0)
|
if (r < 0)
|
||||||
return pam_syslog_errno(handle, LOG_ERR, r, "Failed to connect to system bus: %m");
|
return pam_syslog_errno(pamh, LOG_ERR, r, "Failed to connect to system bus: %m");
|
||||||
|
|
||||||
r = sym_pam_set_data(handle, d->cache_id, d, pam_bus_data_destroy);
|
r = sym_pam_set_data(pamh, d->cache_id, d, pam_bus_data_destroy);
|
||||||
if (r != PAM_SUCCESS)
|
if (r != PAM_SUCCESS)
|
||||||
return pam_syslog_pam_error(handle, LOG_ERR, r, "Failed to set PAM bus data: @PAMERR@");
|
return pam_syslog_pam_error(pamh, LOG_ERR, r, "Failed to set PAM bus data: @PAMERR@");
|
||||||
|
|
||||||
pam_debug_syslog(handle, debug, "New sd-bus connection (%s) opened.", d->cache_id);
|
pam_debug_syslog(pamh, debug, "New sd-bus connection (%s) opened.", d->cache_id);
|
||||||
|
|
||||||
success:
|
success:
|
||||||
*ret_bus = sd_bus_ref(d->bus);
|
*ret_bus = sd_bus_ref(d->bus);
|
||||||
@ -253,38 +253,34 @@ success:
|
|||||||
return PAM_SUCCESS;
|
return PAM_SUCCESS;
|
||||||
}
|
}
|
||||||
|
|
||||||
int pam_get_bus_data(
|
int pam_get_bus_data(pam_handle_t *pamh, const char *module_name, PamBusData **ret) {
|
||||||
pam_handle_t *handle,
|
|
||||||
const char *module_name,
|
|
||||||
PamBusData **ret) {
|
|
||||||
|
|
||||||
PamBusData *d = NULL;
|
PamBusData *d = NULL;
|
||||||
_cleanup_free_ char *cache_id = NULL;
|
_cleanup_free_ char *cache_id = NULL;
|
||||||
int r;
|
int r;
|
||||||
|
|
||||||
assert(handle);
|
assert(pamh);
|
||||||
assert(module_name);
|
assert(module_name);
|
||||||
assert(ret);
|
assert(ret);
|
||||||
|
|
||||||
cache_id = pam_make_bus_cache_id(module_name);
|
cache_id = pam_make_bus_cache_id(module_name);
|
||||||
if (!cache_id)
|
if (!cache_id)
|
||||||
return pam_log_oom(handle);
|
return pam_log_oom(pamh);
|
||||||
|
|
||||||
/* We cache the bus connection so that we can share it between the session and the authentication hooks */
|
/* We cache the bus connection so that we can share it between the session and the authentication hooks */
|
||||||
r = sym_pam_get_data(handle, cache_id, (const void**) &d);
|
r = sym_pam_get_data(pamh, cache_id, (const void**) &d);
|
||||||
if (!IN_SET(r, PAM_SUCCESS, PAM_NO_MODULE_DATA))
|
if (!IN_SET(r, PAM_SUCCESS, PAM_NO_MODULE_DATA))
|
||||||
return pam_syslog_pam_error(handle, LOG_ERR, r, "Failed to get bus connection: @PAMERR@");
|
return pam_syslog_pam_error(pamh, LOG_ERR, r, "Failed to get bus connection: @PAMERR@");
|
||||||
|
|
||||||
*ret = d;
|
*ret = d;
|
||||||
return PAM_SUCCESS;
|
return PAM_SUCCESS;
|
||||||
}
|
}
|
||||||
|
|
||||||
void pam_cleanup_free(pam_handle_t *handle, void *data, int error_status) {
|
void pam_cleanup_free(pam_handle_t *pamh, void *data, int error_status) {
|
||||||
/* A generic destructor for pam_set_data() that just frees the specified data */
|
/* A generic destructor for pam_set_data() that just frees the specified data */
|
||||||
free(data);
|
free(data);
|
||||||
}
|
}
|
||||||
|
|
||||||
void pam_cleanup_close(pam_handle_t *handle, void *data, int error_status) {
|
void pam_cleanup_close(pam_handle_t *pamh, void *data, int error_status) {
|
||||||
|
|
||||||
/* A generic destructor for pam_set_data() that just closes the specified fd.
|
/* A generic destructor for pam_set_data() that just closes the specified fd.
|
||||||
*
|
*
|
||||||
@ -298,13 +294,13 @@ void pam_cleanup_close(pam_handle_t *handle, void *data, int error_status) {
|
|||||||
safe_close(PTR_TO_FD(data));
|
safe_close(PTR_TO_FD(data));
|
||||||
}
|
}
|
||||||
|
|
||||||
int pam_get_item_many_internal(pam_handle_t *handle, ...) {
|
int pam_get_item_many_internal(pam_handle_t *pamh, ...) {
|
||||||
va_list ap;
|
va_list ap;
|
||||||
int r;
|
int r;
|
||||||
|
|
||||||
assert(handle);
|
assert(pamh);
|
||||||
|
|
||||||
va_start(ap, handle);
|
va_start(ap, pamh);
|
||||||
for (;;) {
|
for (;;) {
|
||||||
int item_type = va_arg(ap, int);
|
int item_type = va_arg(ap, int);
|
||||||
if (item_type <= 0) {
|
if (item_type <= 0) {
|
||||||
@ -313,7 +309,7 @@ int pam_get_item_many_internal(pam_handle_t *handle, ...) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
const void **value = ASSERT_PTR(va_arg(ap, const void **));
|
const void **value = ASSERT_PTR(va_arg(ap, const void **));
|
||||||
r = sym_pam_get_item(handle, item_type, value);
|
r = sym_pam_get_item(pamh, item_type, value);
|
||||||
if (!IN_SET(r, PAM_BAD_ITEM, PAM_SUCCESS))
|
if (!IN_SET(r, PAM_BAD_ITEM, PAM_SUCCESS))
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
@ -322,13 +318,13 @@ int pam_get_item_many_internal(pam_handle_t *handle, ...) {
|
|||||||
return r;
|
return r;
|
||||||
}
|
}
|
||||||
|
|
||||||
int pam_get_data_many_internal(pam_handle_t *handle, ...) {
|
int pam_get_data_many_internal(pam_handle_t *pamh, ...) {
|
||||||
va_list ap;
|
va_list ap;
|
||||||
int r;
|
int r;
|
||||||
|
|
||||||
assert(handle);
|
assert(pamh);
|
||||||
|
|
||||||
va_start(ap, handle);
|
va_start(ap, pamh);
|
||||||
for (;;) {
|
for (;;) {
|
||||||
const char *data_name = va_arg(ap, const char *);
|
const char *data_name = va_arg(ap, const char *);
|
||||||
if (!data_name) {
|
if (!data_name) {
|
||||||
@ -337,7 +333,7 @@ int pam_get_data_many_internal(pam_handle_t *handle, ...) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
const void **value = ASSERT_PTR(va_arg(ap, const void **));
|
const void **value = ASSERT_PTR(va_arg(ap, const void **));
|
||||||
r = sym_pam_get_data(handle, data_name, value);
|
r = sym_pam_get_data(pamh, data_name, value);
|
||||||
if (!IN_SET(r, PAM_NO_MODULE_DATA, PAM_SUCCESS))
|
if (!IN_SET(r, PAM_NO_MODULE_DATA, PAM_SUCCESS))
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
@ -346,11 +342,11 @@ int pam_get_data_many_internal(pam_handle_t *handle, ...) {
|
|||||||
return r;
|
return r;
|
||||||
}
|
}
|
||||||
|
|
||||||
int pam_prompt_graceful(pam_handle_t *handle, int style, char **ret_response, const char *fmt, ...) {
|
int pam_prompt_graceful(pam_handle_t *pamh, int style, char **ret_response, const char *fmt, ...) {
|
||||||
va_list args;
|
va_list args;
|
||||||
int r;
|
int r;
|
||||||
|
|
||||||
assert(handle);
|
assert(pamh);
|
||||||
assert(fmt);
|
assert(fmt);
|
||||||
|
|
||||||
/* This is just like pam_prompt(), but does not noisily (i.e. beyond LOG_DEBUG) log on its own, but leaves that to the caller */
|
/* This is just like pam_prompt(), but does not noisily (i.e. beyond LOG_DEBUG) log on its own, but leaves that to the caller */
|
||||||
@ -363,11 +359,11 @@ int pam_prompt_graceful(pam_handle_t *handle, int style, char **ret_response, co
|
|||||||
return PAM_BUF_ERR;
|
return PAM_BUF_ERR;
|
||||||
|
|
||||||
const struct pam_conv *conv = NULL;
|
const struct pam_conv *conv = NULL;
|
||||||
r = sym_pam_get_item(handle, PAM_CONV, (const void**) &conv);
|
r = sym_pam_get_item(pamh, PAM_CONV, (const void**) &conv);
|
||||||
if (!IN_SET(r, PAM_SUCCESS, PAM_BAD_ITEM))
|
if (!IN_SET(r, PAM_SUCCESS, PAM_BAD_ITEM))
|
||||||
return pam_syslog_pam_error(handle, LOG_DEBUG, r, "Failed to get conversation function structure: @PAMERR@");
|
return pam_syslog_pam_error(pamh, LOG_DEBUG, r, "Failed to get conversation function structure: @PAMERR@");
|
||||||
if (!conv || !conv->conv) {
|
if (!conv || !conv->conv) {
|
||||||
sym_pam_syslog(handle, LOG_DEBUG, "No conversation function.");
|
sym_pam_syslog(pamh, LOG_DEBUG, "No conversation function.");
|
||||||
return PAM_SYSTEM_ERR;
|
return PAM_SYSTEM_ERR;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -380,7 +376,7 @@ int pam_prompt_graceful(pam_handle_t *handle, int style, char **ret_response, co
|
|||||||
r = conv->conv(1, &pmessage, &response, conv->appdata_ptr);
|
r = conv->conv(1, &pmessage, &response, conv->appdata_ptr);
|
||||||
_cleanup_(erase_and_freep) char *rr = response ? response->resp : NULL; /* make sure string is freed + erased */
|
_cleanup_(erase_and_freep) char *rr = response ? response->resp : NULL; /* make sure string is freed + erased */
|
||||||
if (r != PAM_SUCCESS)
|
if (r != PAM_SUCCESS)
|
||||||
return pam_syslog_pam_error(handle, LOG_DEBUG, r, "Conversation function failed: @PAMERR@");
|
return pam_syslog_pam_error(pamh, LOG_DEBUG, r, "Conversation function failed: @PAMERR@");
|
||||||
|
|
||||||
if (ret_response)
|
if (ret_response)
|
||||||
*ret_response = TAKE_PTR(rr);
|
*ret_response = TAKE_PTR(rr);
|
||||||
|
|||||||
@ -33,9 +33,9 @@ void pam_log_setup(void);
|
|||||||
|
|
||||||
int errno_to_pam_error(int error) _const_;
|
int errno_to_pam_error(int error) _const_;
|
||||||
|
|
||||||
int pam_syslog_errno(pam_handle_t *handle, int level, int error, const char *format, ...) _printf_(4,5);
|
int pam_syslog_errno(pam_handle_t *pamh, int level, int error, const char *format, ...) _printf_(4,5);
|
||||||
|
|
||||||
int pam_syslog_pam_error(pam_handle_t *handle, int level, int error, const char *format, ...) _printf_(4,5);
|
int pam_syslog_pam_error(pam_handle_t *pamh, int level, int error, const char *format, ...) _printf_(4,5);
|
||||||
|
|
||||||
/* Call sym_pam_syslog if debug is enabled */
|
/* Call sym_pam_syslog if debug is enabled */
|
||||||
#define pam_debug_syslog(handle, debug, fmt, ...) \
|
#define pam_debug_syslog(handle, debug, fmt, ...) \
|
||||||
@ -53,19 +53,19 @@ int pam_syslog_pam_error(pam_handle_t *handle, int level, int error, const char
|
|||||||
errno_to_pam_error(_error); \
|
errno_to_pam_error(_error); \
|
||||||
})
|
})
|
||||||
|
|
||||||
static inline int pam_log_oom(pam_handle_t *handle) {
|
static inline int pam_log_oom(pam_handle_t *pamh) {
|
||||||
/* This is like log_oom(), but uses PAM logging */
|
/* This is like log_oom(), but uses PAM logging */
|
||||||
return pam_syslog_errno(handle, LOG_ERR, ENOMEM, "Out of memory.");
|
return pam_syslog_errno(pamh, LOG_ERR, ENOMEM, "Out of memory.");
|
||||||
}
|
}
|
||||||
|
|
||||||
static inline int pam_bus_log_create_error(pam_handle_t *handle, int r) {
|
static inline int pam_bus_log_create_error(pam_handle_t *pamh, int r) {
|
||||||
/* This is like bus_log_create_error(), but uses PAM logging */
|
/* This is like bus_log_create_error(), but uses PAM logging */
|
||||||
return pam_syslog_errno(handle, LOG_ERR, r, "Failed to create bus message: %m");
|
return pam_syslog_errno(pamh, LOG_ERR, r, "Failed to create bus message: %m");
|
||||||
}
|
}
|
||||||
|
|
||||||
static inline int pam_bus_log_parse_error(pam_handle_t *handle, int r) {
|
static inline int pam_bus_log_parse_error(pam_handle_t *pamh, int r) {
|
||||||
/* This is like bus_log_parse_error(), but uses PAM logging */
|
/* This is like bus_log_parse_error(), but uses PAM logging */
|
||||||
return pam_syslog_errno(handle, LOG_ERR, r, "Failed to parse bus message: %m");
|
return pam_syslog_errno(pamh, LOG_ERR, r, "Failed to parse bus message: %m");
|
||||||
}
|
}
|
||||||
|
|
||||||
typedef struct PamBusData PamBusData;
|
typedef struct PamBusData PamBusData;
|
||||||
@ -74,23 +74,23 @@ void pam_bus_data_disconnectp(PamBusData **d);
|
|||||||
/* Use a different module name per different PAM module. They are all loaded in the same namespace, and this
|
/* Use a different module name per different PAM module. They are all loaded in the same namespace, and this
|
||||||
* helps avoid a clash in the internal data structures of sd-bus. It will be used as key for cache items. */
|
* helps avoid a clash in the internal data structures of sd-bus. It will be used as key for cache items. */
|
||||||
int pam_acquire_bus_connection(
|
int pam_acquire_bus_connection(
|
||||||
pam_handle_t *handle,
|
pam_handle_t *pamh,
|
||||||
const char *module_name,
|
const char *module_name,
|
||||||
bool debug,
|
bool debug,
|
||||||
sd_bus **ret_bus,
|
sd_bus **ret_bus,
|
||||||
PamBusData **ret_pam_bus_data);
|
PamBusData **ret_pam_bus_data);
|
||||||
int pam_get_bus_data(pam_handle_t *handle, const char *module_name, PamBusData **ret);
|
int pam_get_bus_data(pam_handle_t *pamh, const char *module_name, PamBusData **ret);
|
||||||
|
|
||||||
void pam_cleanup_free(pam_handle_t *handle, void *data, int error_status);
|
void pam_cleanup_free(pam_handle_t *pamh, void *data, int error_status);
|
||||||
void pam_cleanup_close(pam_handle_t *handle, void *data, int error_status);
|
void pam_cleanup_close(pam_handle_t *pamh, void *data, int error_status);
|
||||||
|
|
||||||
int pam_get_item_many_internal(pam_handle_t *handle, ...);
|
int pam_get_item_many_internal(pam_handle_t *pamh, ...);
|
||||||
#define pam_get_item_many(handle, ...) pam_get_item_many_internal(handle, __VA_ARGS__, -1)
|
#define pam_get_item_many(handle, ...) pam_get_item_many_internal(handle, __VA_ARGS__, -1)
|
||||||
|
|
||||||
int pam_get_data_many_internal(pam_handle_t *handle, ...) _sentinel_;
|
int pam_get_data_many_internal(pam_handle_t *pamh, ...) _sentinel_;
|
||||||
#define pam_get_data_many(handle, ...) pam_get_data_many_internal(handle, __VA_ARGS__, NULL)
|
#define pam_get_data_many(handle, ...) pam_get_data_many_internal(handle, __VA_ARGS__, NULL)
|
||||||
|
|
||||||
int pam_prompt_graceful(pam_handle_t *handle, int style, char **ret_response, const char *fmt, ...) _printf_(4,5);
|
int pam_prompt_graceful(pam_handle_t *pamh, int style, char **ret_response, const char *fmt, ...) _printf_(4,5);
|
||||||
|
|
||||||
#else
|
#else
|
||||||
|
|
||||||
|
|||||||
@ -345,7 +345,7 @@ executables += [
|
|||||||
},
|
},
|
||||||
test_template + {
|
test_template + {
|
||||||
'sources' : files('test-libcrypt-util.c'),
|
'sources' : files('test-libcrypt-util.c'),
|
||||||
'dependencies' : libcrypt,
|
'conditions' : ['HAVE_LIBCRYPT'],
|
||||||
'timeout' : 120,
|
'timeout' : 120,
|
||||||
},
|
},
|
||||||
test_template + {
|
test_template + {
|
||||||
|
|||||||
@ -11,6 +11,7 @@
|
|||||||
#include "idn-util.h"
|
#include "idn-util.h"
|
||||||
#include "libarchive-util.h"
|
#include "libarchive-util.h"
|
||||||
#include "libaudit-util.h"
|
#include "libaudit-util.h"
|
||||||
|
#include "libcrypt-util.h"
|
||||||
#include "libfido2-util.h"
|
#include "libfido2-util.h"
|
||||||
#include "libmount-util.h"
|
#include "libmount-util.h"
|
||||||
#include "main-func.h"
|
#include "main-func.h"
|
||||||
@ -52,6 +53,7 @@ static int run(int argc, char **argv) {
|
|||||||
ASSERT_DLOPEN(dlopen_libarchive, HAVE_LIBARCHIVE);
|
ASSERT_DLOPEN(dlopen_libarchive, HAVE_LIBARCHIVE);
|
||||||
ASSERT_DLOPEN(dlopen_libaudit, HAVE_AUDIT);
|
ASSERT_DLOPEN(dlopen_libaudit, HAVE_AUDIT);
|
||||||
ASSERT_DLOPEN(dlopen_libblkid, HAVE_BLKID);
|
ASSERT_DLOPEN(dlopen_libblkid, HAVE_BLKID);
|
||||||
|
ASSERT_DLOPEN(dlopen_libcrypt, HAVE_LIBCRYPT);
|
||||||
ASSERT_DLOPEN(dlopen_libfido2, HAVE_LIBFIDO2);
|
ASSERT_DLOPEN(dlopen_libfido2, HAVE_LIBFIDO2);
|
||||||
ASSERT_DLOPEN(dlopen_libkmod, HAVE_KMOD);
|
ASSERT_DLOPEN(dlopen_libkmod, HAVE_KMOD);
|
||||||
ASSERT_DLOPEN(dlopen_libmount, HAVE_LIBMOUNT);
|
ASSERT_DLOPEN(dlopen_libmount, HAVE_LIBMOUNT);
|
||||||
|
|||||||
@ -1,41 +1,25 @@
|
|||||||
/* SPDX-License-Identifier: LGPL-2.1-or-later */
|
/* SPDX-License-Identifier: LGPL-2.1-or-later */
|
||||||
|
|
||||||
#include <crypt.h>
|
|
||||||
|
|
||||||
#include "libcrypt-util.h"
|
#include "libcrypt-util.h"
|
||||||
#include "strv.h"
|
#include "strv.h"
|
||||||
#include "tests.h"
|
#include "tests.h"
|
||||||
|
|
||||||
static void test_crypt_preferred_method(void) {
|
TEST(make_salt) {
|
||||||
log_info("/* %s */", __func__);
|
_cleanup_strv_free_ char **l = NULL;
|
||||||
|
|
||||||
log_info("crypt_preferred_method: %s",
|
|
||||||
#if HAVE_CRYPT_PREFERRED_METHOD
|
|
||||||
crypt_preferred_method()
|
|
||||||
#else
|
|
||||||
"(not available)"
|
|
||||||
#endif
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
static void test_make_salt(void) {
|
|
||||||
log_info("/* %s */", __func__);
|
|
||||||
|
|
||||||
for (int i = 0; i < 10; i++) {
|
for (int i = 0; i < 10; i++) {
|
||||||
_cleanup_free_ char *t;
|
_cleanup_free_ char *t;
|
||||||
|
|
||||||
assert_se(make_salt(&t) == 0);
|
ASSERT_OK(make_salt(&t));
|
||||||
log_info("%s", t);
|
log_info("%s", t);
|
||||||
|
|
||||||
|
ASSERT_FALSE(strv_contains(l, t));
|
||||||
|
ASSERT_OK(strv_consume(&l, TAKE_PTR(t)));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static int test_hash_password(void) {
|
TEST(hash_password) {
|
||||||
log_info("/* %s */", __func__);
|
|
||||||
|
|
||||||
/* As a warm-up exercise, check if we can hash passwords. */
|
/* As a warm-up exercise, check if we can hash passwords. */
|
||||||
|
|
||||||
bool have_sane_hash = false;
|
|
||||||
|
|
||||||
FOREACH_STRING(hash,
|
FOREACH_STRING(hash,
|
||||||
"ew3bU1.hoKk4o",
|
"ew3bU1.hoKk4o",
|
||||||
"$1$gc5rWpTB$wK1aul1PyBn9AX1z93stk1",
|
"$1$gc5rWpTB$wK1aul1PyBn9AX1z93stk1",
|
||||||
@ -43,80 +27,46 @@ static int test_hash_password(void) {
|
|||||||
"$5$lGhDrcrao9zb5oIK$05KlOVG3ocknx/ThreqXE/gk.XzFFBMTksc4t2CPDUD",
|
"$5$lGhDrcrao9zb5oIK$05KlOVG3ocknx/ThreqXE/gk.XzFFBMTksc4t2CPDUD",
|
||||||
"$6$c7wB/3GiRk0VHf7e$zXJ7hN0aLZapE.iO4mn/oHu6.prsXTUG/5k1AxpgR85ELolyAcaIGRgzfwJs3isTChMDBjnthZyaMCfCNxo9I.",
|
"$6$c7wB/3GiRk0VHf7e$zXJ7hN0aLZapE.iO4mn/oHu6.prsXTUG/5k1AxpgR85ELolyAcaIGRgzfwJs3isTChMDBjnthZyaMCfCNxo9I.",
|
||||||
"$y$j9T$$9cKOWsAm4m97WiYk61lPPibZpy3oaGPIbsL4koRe/XD") {
|
"$y$j9T$$9cKOWsAm4m97WiYk61lPPibZpy3oaGPIbsL4koRe/XD") {
|
||||||
int b;
|
|
||||||
|
|
||||||
b = test_password_one(hash, "ppp");
|
#ifndef __GLIBC__
|
||||||
log_info("%s: %s", hash, yes_no(b));
|
/* musl does not support yescrypt. */
|
||||||
#if defined(XCRYPT_VERSION_MAJOR)
|
if (hash[1] == 'y') {
|
||||||
/* xcrypt is supposed to always implement all methods. */
|
ASSERT_OK_ZERO(test_password_one(hash, "ppp"));
|
||||||
assert_se(b);
|
continue;
|
||||||
|
}
|
||||||
#endif
|
#endif
|
||||||
|
ASSERT_OK_POSITIVE(test_password_one(hash, "ppp"));
|
||||||
if (b && IN_SET(hash[1], '6', 'y'))
|
|
||||||
have_sane_hash = true;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return have_sane_hash;
|
FOREACH_STRING(i, "abc123", "h⸿sło") {
|
||||||
}
|
_cleanup_free_ char *hashed;
|
||||||
|
|
||||||
static void test_hash_password_full(void) {
|
ASSERT_OK(hash_password(i, &hashed));
|
||||||
log_info("/* %s */", __func__);
|
log_debug("\"%s\" → \"%s\"", i, hashed);
|
||||||
|
|
||||||
_cleanup_free_ void *cd_data = NULL;
|
ASSERT_OK_POSITIVE(test_password_one(hashed, i));
|
||||||
int cd_size = 0;
|
ASSERT_LE(test_password_one(i, hashed), 0); /* We get an error for non-utf8 */
|
||||||
|
ASSERT_OK_ZERO(test_password_one(hashed, "foobar"));
|
||||||
log_info("sizeof(struct crypt_data): %zu bytes", sizeof(struct crypt_data));
|
ASSERT_OK_POSITIVE(test_password_many(STRV_MAKE(hashed), i));
|
||||||
|
ASSERT_OK_ZERO(test_password_many(STRV_MAKE(hashed), "foobar"));
|
||||||
for (unsigned c = 0; c < 2; c++)
|
ASSERT_OK_ZERO(test_password_many(STRV_MAKE(hashed, hashed, hashed), "foobar"));
|
||||||
FOREACH_STRING(i, "abc123", "h⸿sło") {
|
ASSERT_OK_POSITIVE(test_password_many(STRV_MAKE("$y$j9T$dlCXwkX0GC5L6B8Gf.4PN/$VCyEH",
|
||||||
_cleanup_free_ char *hashed;
|
hashed,
|
||||||
|
"$y$j9T$SAayASazWZIQeJd9AS02m/$"),
|
||||||
if (c == 0)
|
i));
|
||||||
assert_se(hash_password_full(i, &cd_data, &cd_size, &hashed) == 0);
|
ASSERT_OK_POSITIVE(test_password_many(STRV_MAKE("$W$j9T$dlCXwkX0GC5L6B8Gf.4PN/$VCyEH", /* no such method exists... */
|
||||||
else
|
hashed,
|
||||||
assert_se(hash_password_full(i, NULL, NULL, &hashed) == 0);
|
"$y$j9T$SAayASazWZIQeJd9AS02m/$"),
|
||||||
log_debug("\"%s\" → \"%s\"", i, hashed);
|
i));
|
||||||
log_info("crypt_r[a] buffer size: %i bytes", cd_size);
|
ASSERT_OK_ZERO(test_password_many(STRV_MAKE("$y$j9T$dlCXwkX0GC5L6B8Gf.4PN/$VCyEH",
|
||||||
|
hashed,
|
||||||
assert_se(test_password_one(hashed, i) == true);
|
"$y$j9T$SAayASazWZIQeJd9AS02m/$"),
|
||||||
assert_se(test_password_one(i, hashed) <= 0); /* We get an error for non-utf8 */
|
""));
|
||||||
assert_se(test_password_one(hashed, "foobar") == false);
|
ASSERT_OK_ZERO(test_password_many(STRV_MAKE("$W$j9T$dlCXwkX0GC5L6B8Gf.4PN/$VCyEH", /* no such method exists... */
|
||||||
assert_se(test_password_many(STRV_MAKE(hashed), i) == true);
|
hashed,
|
||||||
assert_se(test_password_many(STRV_MAKE(hashed), "foobar") == false);
|
"$y$j9T$SAayASazWZIQeJd9AS02m/$"),
|
||||||
assert_se(test_password_many(STRV_MAKE(hashed, hashed, hashed), "foobar") == false);
|
""));
|
||||||
assert_se(test_password_many(STRV_MAKE("$y$j9T$dlCXwkX0GC5L6B8Gf.4PN/$VCyEH",
|
|
||||||
hashed,
|
|
||||||
"$y$j9T$SAayASazWZIQeJd9AS02m/$"),
|
|
||||||
i) == true);
|
|
||||||
assert_se(test_password_many(STRV_MAKE("$W$j9T$dlCXwkX0GC5L6B8Gf.4PN/$VCyEH", /* no such method exists... */
|
|
||||||
hashed,
|
|
||||||
"$y$j9T$SAayASazWZIQeJd9AS02m/$"),
|
|
||||||
i) == true);
|
|
||||||
assert_se(test_password_many(STRV_MAKE("$y$j9T$dlCXwkX0GC5L6B8Gf.4PN/$VCyEH",
|
|
||||||
hashed,
|
|
||||||
"$y$j9T$SAayASazWZIQeJd9AS02m/$"),
|
|
||||||
"") == false);
|
|
||||||
assert_se(test_password_many(STRV_MAKE("$W$j9T$dlCXwkX0GC5L6B8Gf.4PN/$VCyEH", /* no such method exists... */
|
|
||||||
hashed,
|
|
||||||
"$y$j9T$SAayASazWZIQeJd9AS02m/$"),
|
|
||||||
"") == false);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
int main(int argc, char *argv[]) {
|
DEFINE_TEST_MAIN(LOG_DEBUG);
|
||||||
test_setup_logging(LOG_DEBUG);
|
|
||||||
|
|
||||||
#if defined(__powerpc__) && !defined(XCRYPT_VERSION_MAJOR)
|
|
||||||
return log_tests_skipped("crypt_r() causes a buffer overflow on ppc64el, see https://github.com/systemd/systemd/pull/16981#issuecomment-691203787");
|
|
||||||
#endif
|
|
||||||
|
|
||||||
test_crypt_preferred_method();
|
|
||||||
test_make_salt();
|
|
||||||
|
|
||||||
if (!test_hash_password())
|
|
||||||
return log_tests_skipped("crypt doesn't support yescrypt or sha512crypt");
|
|
||||||
|
|
||||||
test_hash_password_full();
|
|
||||||
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|||||||
@ -4,7 +4,6 @@
|
|||||||
|
|
||||||
#include "alloc-util.h"
|
#include "alloc-util.h"
|
||||||
#include "format-util.h"
|
#include "format-util.h"
|
||||||
#include "libcrypt-util.h"
|
|
||||||
#include "log.h"
|
#include "log.h"
|
||||||
#include "memory-util.h"
|
#include "memory-util.h"
|
||||||
#include "path-util.h"
|
#include "path-util.h"
|
||||||
@ -342,18 +341,6 @@ TEST(get_group_creds) {
|
|||||||
test_get_group_creds_one("65534", NOBODY_GROUP_NAME, GID_NOBODY);
|
test_get_group_creds_one("65534", NOBODY_GROUP_NAME, GID_NOBODY);
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST(make_salt) {
|
|
||||||
_cleanup_free_ char *s, *t;
|
|
||||||
|
|
||||||
ASSERT_OK(make_salt(&s));
|
|
||||||
log_info("got %s", s);
|
|
||||||
|
|
||||||
ASSERT_OK(make_salt(&t));
|
|
||||||
log_info("got %s", t);
|
|
||||||
|
|
||||||
ASSERT_NOT_STREQ(s, t);
|
|
||||||
}
|
|
||||||
|
|
||||||
TEST(in_gid) {
|
TEST(in_gid) {
|
||||||
ASSERT_OK(in_gid(getgid()));
|
ASSERT_OK(in_gid(getgid()));
|
||||||
ASSERT_OK(in_gid(getegid()));
|
ASSERT_OK(in_gid(getegid()));
|
||||||
|
|||||||
@ -6,7 +6,7 @@
|
|||||||
# E.g.
|
# E.g.
|
||||||
# tools/setup-musl-build.sh build-musl -Dbuildtype=debugoptimized && ninja -C build-musl
|
# tools/setup-musl-build.sh build-musl -Dbuildtype=debugoptimized && ninja -C build-musl
|
||||||
|
|
||||||
set -eu
|
set -eux
|
||||||
|
|
||||||
BUILD_DIR="${1:?}"
|
BUILD_DIR="${1:?}"
|
||||||
shift
|
shift
|
||||||
@ -53,7 +53,6 @@ LINKS=(
|
|||||||
security
|
security
|
||||||
selinux
|
selinux
|
||||||
sys/acl.h
|
sys/acl.h
|
||||||
sys/capability.h
|
|
||||||
tss2
|
tss2
|
||||||
xen
|
xen
|
||||||
xkbcommon
|
xkbcommon
|
||||||
@ -63,6 +62,7 @@ LINKS=(
|
|||||||
zstd_errors.h
|
zstd_errors.h
|
||||||
)
|
)
|
||||||
|
|
||||||
|
rm -rf "${SETUP_DIR}"
|
||||||
for t in "${LINKS[@]}"; do
|
for t in "${LINKS[@]}"; do
|
||||||
[[ -e /usr/include/"$t" ]]
|
[[ -e /usr/include/"$t" ]]
|
||||||
link="${SETUP_DIR}/usr/include/${t}"
|
link="${SETUP_DIR}/usr/include/${t}"
|
||||||
@ -82,4 +82,4 @@ env \
|
|||||||
CXX=musl-gcc \
|
CXX=musl-gcc \
|
||||||
CFLAGS="$CFLAGS" \
|
CFLAGS="$CFLAGS" \
|
||||||
CXXFLAGS="$CFLAGS" \
|
CXXFLAGS="$CFLAGS" \
|
||||||
meson setup -Ddbus-interfaces-dir=no -Dlibc=musl "${BUILD_DIR}" "${@}"
|
meson setup --reconfigure -Ddbus-interfaces-dir=no -Dlibc=musl "${BUILD_DIR}" "${@}"
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user