diff --git a/src/backlight/backlight.c b/src/backlight/backlight.c index 5a3095cbba..a4e5d77f6c 100644 --- a/src/backlight/backlight.c +++ b/src/backlight/backlight.c @@ -14,10 +14,11 @@ #include "mkdir.h" #include "parse-util.h" #include "pretty-print.h" -#include "terminal-util.h" +#include "process-util.h" #include "reboot-util.h" #include "string-util.h" #include "strv.h" +#include "terminal-util.h" #include "util.h" static int help(void) { @@ -368,7 +369,7 @@ static int run(int argc, char *argv[]) { log_setup(); - if (strv_contains(strv_skip(argv, 1), "--help")) + if (argv_looks_like_help(argc, argv)) return help(); if (argc != 3) diff --git a/src/basic/process-util.c b/src/basic/process-util.c index 72807d039c..10aec10bfa 100644 --- a/src/basic/process-util.c +++ b/src/basic/process-util.c @@ -1615,6 +1615,30 @@ _noreturn_ void freeze(void) { pause(); } +bool argv_looks_like_help(int argc, char **argv) { + char **l; + + /* Scans the command line for indications the user asks for help. This is supposed to be called by + * tools that do not implement getopt() style command line parsing because they are not primarily + * user-facing. Detects four ways of asking for help: + * + * 1. Passing zero arguments + * 2. Passing "help" as first argument + * 3. Passing --help as any argument + * 4. Passing -h as any argument + */ + + if (argc <= 1) + return true; + + if (streq_ptr(argv[1], "help")) + return true; + + l = strv_skip(argv, 1); + + return strv_contains(l, "--help") || + strv_contains(l, "-h"); +} static const char *const sigchld_code_table[] = { [CLD_EXITED] = "exited", diff --git a/src/basic/process-util.h b/src/basic/process-util.h index f22ff76ee8..c07575e580 100644 --- a/src/basic/process-util.h +++ b/src/basic/process-util.h @@ -191,3 +191,5 @@ int setpriority_closest(int priority); bool invoked_as(char *argv[], const char *token); _noreturn_ void freeze(void); + +bool argv_looks_like_help(int argc, char **argv); diff --git a/src/cryptsetup/cryptsetup.c b/src/cryptsetup/cryptsetup.c index 4c514e408f..bd666230be 100644 --- a/src/cryptsetup/cryptsetup.c +++ b/src/cryptsetup/cryptsetup.c @@ -34,6 +34,7 @@ #include "path-util.h" #include "pkcs11-util.h" #include "pretty-print.h" +#include "process-util.h" #include "random-util.h" #include "string-util.h" #include "strv.h" @@ -850,7 +851,7 @@ static int acquire_pins_from_env_variable(char ***ret_pins) { } #endif -static int attach_luks2_by_fido2( +static int attach_luks2_by_fido2_via_plugin( struct crypt_device *cd, const char *name, usec_t until, @@ -980,7 +981,7 @@ static int attach_luks_or_plain_or_bitlk_by_fido2( for (;;) { if (use_libcryptsetup_plugin && !arg_fido2_cid) { - r = attach_luks2_by_fido2(cd, name, until, arg_headless, arg_fido2_device, flags); + r = attach_luks2_by_fido2_via_plugin(cd, name, until, arg_headless, arg_fido2_device, flags); if (IN_SET(r, -ENOTUNIQ, -ENXIO, -ENOENT)) return log_debug_errno(SYNTHETIC_ERRNO(EAGAIN), "Automatic FIDO2 metadata discovery was not possible because missing or not unique, falling back to traditional unlocking."); @@ -1053,7 +1054,7 @@ static int attach_luks_or_plain_or_bitlk_by_fido2( return 0; } -static int attach_luks2_by_pkcs11( +static int attach_luks2_by_pkcs11_via_plugin( struct crypt_device *cd, const char *name, const char *friendly_name, @@ -1133,7 +1134,7 @@ static int attach_luks_or_plain_or_bitlk_by_pkcs11( for (;;) { if (use_libcryptsetup_plugin && arg_pkcs11_uri_auto) - r = attach_luks2_by_pkcs11(cd, name, friendly, until, arg_headless, flags); + r = attach_luks2_by_pkcs11_via_plugin(cd, name, friendly, until, arg_headless, flags); else { r = decrypt_pkcs11_key( name, @@ -1246,7 +1247,7 @@ static int make_tpm2_device_monitor( return 0; } -static int attach_luks2_by_tpm2( +static int attach_luks2_by_tpm2_via_plugin( struct crypt_device *cd, const char *name, uint32_t flags) { @@ -1328,12 +1329,12 @@ static int attach_luks_or_plain_or_bitlk_by_tpm2( return -EAGAIN; /* Mangle error code: let's make any form of TPM2 failure non-fatal. */ } } else { - r = attach_luks2_by_tpm2(cd, name, flags); + r = attach_luks2_by_tpm2_via_plugin(cd, name, flags); /* EAGAIN means: no tpm2 chip found * EOPNOTSUPP means: no libcryptsetup plugins support */ if (r == -ENXIO) - return log_debug_errno(SYNTHETIC_ERRNO(EAGAIN), - "No TPM2 metadata matching the current system state found in LUKS2 header, falling back to traditional unlocking."); + return log_notice_errno(SYNTHETIC_ERRNO(EAGAIN), + "No TPM2 metadata matching the current system state found in LUKS2 header, falling back to traditional unlocking."); if (r == -ENOENT) return log_debug_errno(SYNTHETIC_ERRNO(EAGAIN), "No TPM2 metadata enrolled in LUKS2 header or TPM2 support not available, falling back to traditional unlocking."); @@ -1343,7 +1344,7 @@ static int attach_luks_or_plain_or_bitlk_by_tpm2( } } - if (r == -EOPNOTSUPP) { + if (r == -EOPNOTSUPP) { /* Plugin not available, let's process TPM2 stuff right here instead */ _cleanup_free_ void *blob = NULL, *policy_hash = NULL; size_t blob_size, policy_hash_size; bool found_some = false; @@ -1372,10 +1373,11 @@ static int attach_luks_or_plain_or_bitlk_by_tpm2( &tpm2_flags); if (r == -ENXIO) /* No further TPM2 tokens found in the LUKS2 header. */ - return log_debug_errno(SYNTHETIC_ERRNO(EAGAIN), - found_some - ? "No TPM2 metadata matching the current system state found in LUKS2 header, falling back to traditional unlocking." - : "No TPM2 metadata enrolled in LUKS2 header, falling back to traditional unlocking."); + return log_full_errno(found_some ? LOG_NOTICE : LOG_DEBUG, + SYNTHETIC_ERRNO(EAGAIN), + found_some + ? "No TPM2 metadata matching the current system state found in LUKS2 header, falling back to traditional unlocking." + : "No TPM2 metadata enrolled in LUKS2 header, falling back to traditional unlocking."); if (ERRNO_IS_NOT_SUPPORTED(r)) /* TPM2 support not compiled in? */ return log_debug_errno(SYNTHETIC_ERRNO(EAGAIN), "TPM2 support not available, falling back to traditional unlocking."); if (r < 0) @@ -1398,7 +1400,7 @@ static int attach_luks_or_plain_or_bitlk_by_tpm2( arg_ask_password_flags, &decrypted_key, &decrypted_key_size); if (IN_SET(r, -EACCES, -ENOLCK)) - return log_error_errno(SYNTHETIC_ERRNO(EAGAIN), "TPM2 PIN unlock failed, falling back to traditional unlocking."); + return log_notice_errno(SYNTHETIC_ERRNO(EAGAIN), "TPM2 PIN unlock failed, falling back to traditional unlocking."); if (r != -EPERM) break; @@ -1726,7 +1728,7 @@ static int run(int argc, char *argv[]) { const char *verb; int r; - if (argc <= 1) + if (argv_looks_like_help(argc, argv)) return help(); if (argc < 3) @@ -1758,8 +1760,8 @@ static int run(int argc, char *argv[]) { volume = argv[2]; source = argv[3]; - key_file = argc >= 5 && !STR_IN_SET(argv[4], "", "-", "none") ? argv[4] : NULL; - options = argc >= 6 && !STR_IN_SET(argv[5], "", "-", "none") ? argv[5] : NULL; + key_file = mangle_none(argc >= 5 ? argv[4] : NULL); + options = mangle_none(argc >= 6 ? argv[5] : NULL); if (!filename_is_valid(volume)) return log_error_errno(SYNTHETIC_ERRNO(EINVAL), "Volume name '%s' is not valid.", volume); diff --git a/src/integritysetup/integritysetup.c b/src/integritysetup/integritysetup.c index d8cfd12e95..924c15b6eb 100644 --- a/src/integritysetup/integritysetup.c +++ b/src/integritysetup/integritysetup.c @@ -12,9 +12,10 @@ #include "log.h" #include "main-func.h" #include "memory-util.h" -#include "path-util.h" #include "parse-util.h" +#include "path-util.h" #include "pretty-print.h" +#include "process-util.h" #include "string-util.h" #include "terminal-util.h" @@ -87,19 +88,16 @@ static const char *integrity_algorithm_select(const void *key_file_buf) { static int run(int argc, char *argv[]) { _cleanup_(crypt_freep) struct crypt_device *cd = NULL; + char *verb, *volume; int r; - char *action, *volume; - if (argc <= 1 || - strv_contains(strv_skip(argv, 1), "--help") || - strv_contains(strv_skip(argv, 1), "-h") || - streq(argv[1], "help")) + if (argv_looks_like_help(argc, argv)) return help(); if (argc < 3) return log_error_errno(SYNTHETIC_ERRNO(EINVAL), "This program requires at least two arguments."); - action = argv[1]; + verb = argv[1]; volume = argv[2]; log_setup(); @@ -108,7 +106,7 @@ static int run(int argc, char *argv[]) { umask(0022); - if (streq(action, "attach")) { + if (streq(verb, "attach")) { /* attach name device optional_key_file optional_options */ crypt_status_info status; @@ -123,8 +121,11 @@ static int run(int argc, char *argv[]) { return log_error_errno(SYNTHETIC_ERRNO(EINVAL), "attach has a maximum of five arguments."); device = argv[3]; - key_file = (argc > 4) ? empty_or_dash_to_null(argv[4]) : NULL; - options = (argc > 5) ? empty_or_dash_to_null(argv[5]) : NULL; + key_file = mangle_none(argc > 4 ? argv[4] : NULL); + options = mangle_none(argc > 5 ? argv[5] : NULL); + + if (!filename_is_valid(volume)) + return log_error_errno(SYNTHETIC_ERRNO(EINVAL), "Volume name '%s' is not valid.", volume); if (key_file) { r = load_key_file(key_file, &key_buf, &key_buf_size); @@ -171,14 +172,19 @@ static int run(int argc, char *argv[]) { if (r < 0) return log_error_errno(r, "Failed to set up integrity device: %m"); - } else if (streq(action, "detach")) { + } else if (streq(verb, "detach")) { if (argc > 3) return log_error_errno(SYNTHETIC_ERRNO(EINVAL), "detach has a maximum of two arguments."); + if (!filename_is_valid(volume)) + return log_error_errno(SYNTHETIC_ERRNO(EINVAL), "Volume name '%s' is not valid.", volume); + r = crypt_init_by_name(&cd, volume); - if (r == -ENODEV) + if (r == -ENODEV) { + log_info("Volume %s already inactive.", volume); return 0; + } if (r < 0) return log_error_errno(r, "crypt_init_by_name() failed: %m"); @@ -189,7 +195,7 @@ static int run(int argc, char *argv[]) { return log_error_errno(r, "Failed to deactivate: %m"); } else - return log_error_errno(SYNTHETIC_ERRNO(EINVAL), "Unknown verb %s.", action); + return log_error_errno(SYNTHETIC_ERRNO(EINVAL), "Unknown verb %s.", verb); return 0; } diff --git a/src/shared/cryptsetup-util.h b/src/shared/cryptsetup-util.h index ff44af8441..2a17820d63 100644 --- a/src/shared/cryptsetup-util.h +++ b/src/shared/cryptsetup-util.h @@ -86,3 +86,8 @@ static inline void sym_crypt_free(struct crypt_device* cd) {} static inline void sym_crypt_freep(struct crypt_device** cd) {} #endif + +static inline const char *mangle_none(const char *s) { + /* A helper that turns cryptsetup/integritysetup/veritysetup "options" strings into NULL if they are effectively empty */ + return isempty(s) || STR_IN_SET(s, "-", "none") ? NULL : s; +} diff --git a/src/veritysetup/veritysetup.c b/src/veritysetup/veritysetup.c index 3b5cb53b4a..1d1baaa59d 100644 --- a/src/veritysetup/veritysetup.c +++ b/src/veritysetup/veritysetup.c @@ -12,6 +12,7 @@ #include "main-func.h" #include "path-util.h" #include "pretty-print.h" +#include "process-util.h" #include "string-util.h" #include "terminal-util.h" @@ -111,12 +112,10 @@ static int parse_options(const char *options) { static int run(int argc, char *argv[]) { _cleanup_(crypt_freep) struct crypt_device *cd = NULL; + const char *verb; int r; - if (argc <= 1 || - strv_contains(strv_skip(argv, 1), "--help") || - strv_contains(strv_skip(argv, 1), "-h") || - streq(argv[1], "help")) + if (argv_looks_like_help(argc, argv)) return help(); if (argc < 3) @@ -128,7 +127,10 @@ static int run(int argc, char *argv[]) { umask(0022); - if (streq(argv[1], "attach")) { + verb = argv[1]; + + if (streq(verb, "attach")) { + const char *volume, *data_device, *verity_device, *root_hash, *options; _cleanup_free_ void *m = NULL; crypt_status_info status; size_t l; @@ -136,24 +138,33 @@ static int run(int argc, char *argv[]) { if (argc < 6) return log_error_errno(SYNTHETIC_ERRNO(EINVAL), "attach requires at least four arguments."); - r = unhexmem(argv[5], strlen(argv[5]), &m, &l); + volume = argv[2]; + data_device = argv[3]; + verity_device = argv[4]; + root_hash = argv[5]; + options = mangle_none(argc > 6 ? argv[6] : NULL); + + if (!filename_is_valid(volume)) + return log_error_errno(SYNTHETIC_ERRNO(EINVAL), "Volume name '%s' is not valid.", volume); + + r = unhexmem(root_hash, SIZE_MAX, &m, &l); if (r < 0) return log_error_errno(r, "Failed to parse root hash: %m"); - r = crypt_init(&cd, argv[4]); + r = crypt_init(&cd, verity_device); if (r < 0) - return log_error_errno(r, "Failed to open verity device %s: %m", argv[4]); + return log_error_errno(r, "Failed to open verity device %s: %m", verity_device); cryptsetup_enable_logging(cd); - status = crypt_status(cd, argv[2]); + status = crypt_status(cd, volume); if (IN_SET(status, CRYPT_ACTIVE, CRYPT_BUSY)) { - log_info("Volume %s already active.", argv[2]); + log_info("Volume %s already active.", volume); return 0; } - if (argc > 6) { - r = parse_options(argv[6]); + if (options) { + r = parse_options(options); if (r < 0) return log_error_errno(r, "Failed to parse options: %m"); } @@ -162,7 +173,7 @@ static int run(int argc, char *argv[]) { if (r < 0) return log_error_errno(r, "Failed to load verity superblock: %m"); - r = crypt_set_data_device(cd, argv[3]); + r = crypt_set_data_device(cd, data_device); if (r < 0) return log_error_errno(r, "Failed to configure data device: %m"); @@ -186,20 +197,26 @@ static int run(int argc, char *argv[]) { return log_error_errno(r, "Failed to read root hash signature: %m"); } - r = crypt_activate_by_signed_key(cd, argv[2], m, l, hash_sig, hash_sig_size, arg_activate_flags); + r = crypt_activate_by_signed_key(cd, volume, m, l, hash_sig, hash_sig_size, arg_activate_flags); #else assert_not_reached(); #endif } else - r = crypt_activate_by_volume_key(cd, argv[2], m, l, arg_activate_flags); + r = crypt_activate_by_volume_key(cd, volume, m, l, arg_activate_flags); if (r < 0) return log_error_errno(r, "Failed to set up verity device: %m"); - } else if (streq(argv[1], "detach")) { + } else if (streq(verb, "detach")) { + const char *volume; - r = crypt_init_by_name(&cd, argv[2]); + volume = argv[2]; + + if (!filename_is_valid(volume)) + return log_error_errno(SYNTHETIC_ERRNO(EINVAL), "Volume name '%s' is not valid.", volume); + + r = crypt_init_by_name(&cd, volume); if (r == -ENODEV) { - log_info("Volume %s already inactive.", argv[2]); + log_info("Volume %s already inactive.", volume); return 0; } if (r < 0) @@ -207,12 +224,12 @@ static int run(int argc, char *argv[]) { cryptsetup_enable_logging(cd); - r = crypt_deactivate(cd, argv[2]); + r = crypt_deactivate(cd, volume); if (r < 0) return log_error_errno(r, "Failed to deactivate: %m"); } else - return log_error_errno(SYNTHETIC_ERRNO(EINVAL), "Unknown verb %s.", argv[1]); + return log_error_errno(SYNTHETIC_ERRNO(EINVAL), "Unknown verb %s.", verb); return 0; }