#include "sd-bus.h"
#include "ask-password-api.h"
+#include "build.h"
#include "bus-common-errors.h"
#include "bus-error.h"
#include "bus-locator.h"
+#include "cap-list.h"
+#include "capability-util.h"
#include "cgroup-util.h"
#include "dns-domain.h"
#include "env-util.h"
#include "spawn-polkit-agent.h"
#include "terminal-util.h"
#include "uid-alloc-range.h"
+#include "user-record.h"
#include "user-record-pwquality.h"
#include "user-record-show.h"
#include "user-record-util.h"
-#include "user-record.h"
#include "user-util.h"
#include "verbs.h"
EXPORT_FORMAT_STRIPPED, /* strip "state" + "binding", but leave signature in place */
EXPORT_FORMAT_MINIMAL, /* also strip signature */
} arg_export_format = EXPORT_FORMAT_FULL;
+static uint64_t arg_capability_bounding_set = UINT64_MAX;
+static uint64_t arg_capability_ambient_set = UINT64_MAX;
STATIC_DESTRUCTOR_REGISTER(arg_identity_extra, json_variant_unrefp);
STATIC_DESTRUCTOR_REGISTER(arg_identity_extra_this_machine, json_variant_unrefp);
int r;
if (arg_pkcs11_token_uri)
- return log_error_errno(SYNTHETIC_ERRNO(EINVAL), "To change the PKCS#11 security token use 'homectl update --pkcs11-token-uri=…'.");
+ return log_error_errno(SYNTHETIC_ERRNO(EINVAL),
+ "To change the PKCS#11 security token use 'homectl update --pkcs11-token-uri=%s'.",
+ special_glyph(SPECIAL_GLYPH_ELLIPSIS));
if (arg_fido2_device)
- return log_error_errno(SYNTHETIC_ERRNO(EINVAL), "To change the FIDO2 security token use 'homectl update --fido2-device=…'.");
+ return log_error_errno(SYNTHETIC_ERRNO(EINVAL),
+ "To change the FIDO2 security token use 'homectl update --fido2-device=%s'.",
+ special_glyph(SPECIAL_GLYPH_ELLIPSIS));
if (identity_properties_specified())
return log_error_errno(SYNTHETIC_ERRNO(EINVAL), "The 'passwd' verb does not permit changing other record properties at the same time.");
_cleanup_(sd_bus_message_unrefp) sd_bus_message *m = NULL, *reply = NULL;
_cleanup_(sd_bus_flush_close_unrefp) sd_bus *bus = NULL;
_cleanup_(user_record_unrefp) UserRecord *secret = NULL;
- _cleanup_close_ int acquired_fd = -1;
+ _cleanup_close_ int acquired_fd = -EBADF;
_cleanup_strv_free_ char **cmdline = NULL;
const char *home;
int r, ret;
" -d --home-dir=PATH Home directory\n"
" -u --uid=UID Numeric UID for user\n"
" -G --member-of=GROUP Add user to group\n"
+ " --capability-bounding-set=CAPS\n"
+ " Bounding POSIX capability set\n"
+ " --capability-ambient-set=CAPS\n"
+ " Ambient POSIX capability set\n"
" --skel=PATH Skeleton directory to use\n"
" --shell=PATH Shell for account\n"
" --setenv=VARIABLE[=VALUE] Set an environment variable at log-in\n"
" Memory cost for PBKDF in bytes\n"
" --luks-pbkdf-parallel-threads=NUMBER\n"
" Number of parallel threads for PKBDF\n"
+ " --luks-sector-size=BYTES\n"
+ " Sector size for LUKS encryption in bytes\n"
" --luks-extra-mount-options=OPTIONS\n"
" LUKS extra mount options\n"
" --auto-resize-mode=MODE Automatically grow/shrink home on login/logout\n"
ARG_IO_WEIGHT,
ARG_LUKS_PBKDF_TYPE,
ARG_LUKS_PBKDF_HASH_ALGORITHM,
+ ARG_LUKS_PBKDF_FORCE_ITERATIONS,
ARG_LUKS_PBKDF_TIME_COST,
ARG_LUKS_PBKDF_MEMORY_COST,
ARG_LUKS_PBKDF_PARALLEL_THREADS,
+ ARG_LUKS_SECTOR_SIZE,
ARG_RATE_LIMIT_INTERVAL,
ARG_RATE_LIMIT_BURST,
ARG_STOP_DELAY,
ARG_AUTO_RESIZE_MODE,
ARG_REBALANCE_WEIGHT,
ARG_FIDO2_CRED_ALG,
+ ARG_CAPABILITY_BOUNDING_SET,
+ ARG_CAPABILITY_AMBIENT_SET,
};
static const struct option options[] = {
{ "luks-volume-key-size", required_argument, NULL, ARG_LUKS_VOLUME_KEY_SIZE },
{ "luks-pbkdf-type", required_argument, NULL, ARG_LUKS_PBKDF_TYPE },
{ "luks-pbkdf-hash-algorithm", required_argument, NULL, ARG_LUKS_PBKDF_HASH_ALGORITHM },
+ { "luks-pbkdf-force-iterations", required_argument, NULL, ARG_LUKS_PBKDF_FORCE_ITERATIONS },
{ "luks-pbkdf-time-cost", required_argument, NULL, ARG_LUKS_PBKDF_TIME_COST },
{ "luks-pbkdf-memory-cost", required_argument, NULL, ARG_LUKS_PBKDF_MEMORY_COST },
{ "luks-pbkdf-parallel-threads", required_argument, NULL, ARG_LUKS_PBKDF_PARALLEL_THREADS },
+ { "luks-sector-size", required_argument, NULL, ARG_LUKS_SECTOR_SIZE },
{ "nosuid", required_argument, NULL, ARG_NOSUID },
{ "nodev", required_argument, NULL, ARG_NODEV },
{ "noexec", required_argument, NULL, ARG_NOEXEC },
{ "luks-extra-mount-options", required_argument, NULL, ARG_LUKS_EXTRA_MOUNT_OPTIONS },
{ "auto-resize-mode", required_argument, NULL, ARG_AUTO_RESIZE_MODE },
{ "rebalance-weight", required_argument, NULL, ARG_REBALANCE_WEIGHT },
+ { "capability-bounding-set", required_argument, NULL, ARG_CAPABILITY_BOUNDING_SET },
+ { "capability-ambient-set", required_argument, NULL, ARG_CAPABILITY_AMBIENT_SET },
{}
};
break;
case ARG_LUKS_VOLUME_KEY_SIZE:
+ case ARG_LUKS_PBKDF_FORCE_ITERATIONS:
case ARG_LUKS_PBKDF_PARALLEL_THREADS:
case ARG_RATE_LIMIT_BURST: {
const char *field =
c == ARG_LUKS_VOLUME_KEY_SIZE ? "luksVolumeKeySize" :
+ c == ARG_LUKS_PBKDF_FORCE_ITERATIONS ? "luksPbkdfForceIterations" :
c == ARG_LUKS_PBKDF_PARALLEL_THREADS ? "luksPbkdfParallelThreads" :
c == ARG_RATE_LIMIT_BURST ? "rateLimitBurst" : NULL;
unsigned n;
break;
}
+ case ARG_LUKS_SECTOR_SIZE: {
+ uint64_t ss;
+
+ if (isempty(optarg)) {
+ r = drop_from_identity("luksSectorSize");
+ if (r < 0)
+ return r;
+
+ break;
+ }
+
+ r = parse_sector_size(optarg, &ss);
+ if (r < 0)
+ return r;
+
+ r = json_variant_set_field_unsigned(&arg_identity_extra, "luksSectorSize", ss);
+ if (r < 0)
+ return log_error_errno(r, "Failed to set sector size field: %m");
+
+ break;
+ }
+
case ARG_UMASK: {
mode_t m;
r = drop_from_identity("rebalanceWeight");
if (r < 0)
return r;
+ break;
}
if (streq(optarg, "off"))
return log_error_errno(r, "Failed to parse --rebalance-weight= argument: %s", optarg);
if (u < REBALANCE_WEIGHT_MIN || u > REBALANCE_WEIGHT_MAX)
- return log_error_errno(SYNTHETIC_ERRNO(ERANGE), "Rebalancing weight out of valid range %" PRIu64 "…%" PRIu64 ": %s",
- REBALANCE_WEIGHT_MIN, REBALANCE_WEIGHT_MAX, optarg);
+ return log_error_errno(SYNTHETIC_ERRNO(ERANGE), "Rebalancing weight out of valid range %" PRIu64 "%s%" PRIu64 ": %s",
+ REBALANCE_WEIGHT_MIN, special_glyph(SPECIAL_GLYPH_ELLIPSIS), REBALANCE_WEIGHT_MAX, optarg);
}
/* Drop from per machine stuff and everywhere */
r = drop_from_identity("dropCaches");
if (r < 0)
return r;
+ break;
}
r = parse_boolean_argument("--drop-caches=", optarg, &drop_caches);
break;
}
+ case ARG_CAPABILITY_AMBIENT_SET:
+ case ARG_CAPABILITY_BOUNDING_SET: {
+ _cleanup_strv_free_ char **l = NULL;
+ bool subtract = false;
+ uint64_t parsed, *which, updated;
+ const char *p, *field;
+
+ if (c == ARG_CAPABILITY_AMBIENT_SET) {
+ which = &arg_capability_ambient_set;
+ field = "capabilityAmbientSet";
+ } else {
+ assert(c == ARG_CAPABILITY_BOUNDING_SET);
+ which = &arg_capability_bounding_set;
+ field = "capabilityBoundingSet";
+ }
+
+ if (isempty(optarg)) {
+ r = drop_from_identity(field);
+ if (r < 0)
+ return r;
+
+ *which = UINT64_MAX;
+ break;
+ }
+
+ p = optarg;
+ if (*p == '~') {
+ subtract = true;
+ p++;
+ }
+
+ r = capability_set_from_string(p, &parsed);
+ if (r == 0)
+ return log_error_errno(SYNTHETIC_ERRNO(EINVAL), "Invalid capabilities in capability string '%s'.", p);
+ if (r < 0)
+ return log_error_errno(r, "Failed to parse capability string '%s': %m", p);
+
+ if (*which == UINT64_MAX)
+ updated = subtract ? all_capabilities() & ~parsed : parsed;
+ else if (subtract)
+ updated = *which & ~parsed;
+ else
+ updated = *which | parsed;
+
+ if (capability_set_to_strv(updated, &l) < 0)
+ return log_oom();
+
+ r = json_variant_set_field_strv(&arg_identity_extra, field, l);
+ if (r < 0)
+ return log_error_errno(r, "Failed to set %s field: %m", field);
+
+ *which = updated;
+ break;
+ }
+
case '?':
return -EINVAL;