]> git.ipfire.org Git - thirdparty/systemd.git/blobdiff - src/home/homectl.c
homectl: make the new caps field configurable via homectl
[thirdparty/systemd.git] / src / home / homectl.c
index 0a4c01834aa3465c7d1a0da15e5f9048fab1b532..531b685e22dd850db53fcb07b28214e6c323c9fc 100644 (file)
@@ -9,6 +9,8 @@
 #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"
 
@@ -76,6 +78,8 @@ static enum {
         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);
@@ -1798,26 +1802,6 @@ static int parse_disk_size(const char *t, uint64_t *ret) {
         return 0;
 }
 
-static int parse_sector_size(const char *t, uint64_t *ret) {
-        int r;
-
-        assert(t);
-        assert(ret);
-
-        uint64_t ss;
-
-        r = safe_atou64(t, &ss);
-        if (r < 0)
-                return log_error_errno(r, "Failed to parse sector size parameter %s", t);
-        if (ss < 512 || ss > 4096) /* Allow up to 4K due to dm-crypt support and 4K alignment by the homed LUKS backend */
-                return log_error_errno(SYNTHETIC_ERRNO(ERANGE), "Sector size not between 512 and 4096: %s", t);
-        if (!ISPOWEROF2(ss))
-                return log_error_errno(SYNTHETIC_ERRNO(EINVAL), "Sector size not power of 2: %s", t);
-
-        *ret = ss;
-        return 0;
-}
-
 static int resize_home(int argc, char *argv[], void *userdata) {
         _cleanup_(sd_bus_flush_close_unrefp) sd_bus *bus = NULL;
         _cleanup_(user_record_unrefp) UserRecord *secret = NULL;
@@ -2230,6 +2214,10 @@ static int help(int argc, char *argv[], void *userdata) {
                "  -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"
@@ -2422,6 +2410,8 @@ static int parse_argv(int argc, char *argv[]) {
                 ARG_AUTO_RESIZE_MODE,
                 ARG_REBALANCE_WEIGHT,
                 ARG_FIDO2_CRED_ALG,
+                ARG_CAPABILITY_BOUNDING_SET,
+                ARG_CAPABILITY_AMBIENT_SET,
         };
 
         static const struct option options[] = {
@@ -2512,6 +2502,8 @@ static int parse_argv(int argc, char *argv[]) {
                 { "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      },
                 {}
         };
 
@@ -3658,6 +3650,7 @@ static int parse_argv(int argc, char *argv[]) {
                                 r = drop_from_identity("rebalanceWeight");
                                 if (r < 0)
                                         return r;
+                                break;
                         }
 
                         if (streq(optarg, "off"))
@@ -3740,6 +3733,7 @@ static int parse_argv(int argc, char *argv[]) {
                                 r = drop_from_identity("dropCaches");
                                 if (r < 0)
                                         return r;
+                                break;
                         }
 
                         r = parse_boolean_argument("--drop-caches=", optarg, &drop_caches);
@@ -3753,6 +3747,61 @@ static int parse_argv(int argc, char *argv[]) {
                         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;