Whamcloud - gitweb
LU-17410 sec: per-nodemap capabilities mask 38/57938/16
authorSebastien Buisson <sbuisson@ddn.com>
Mon, 27 Jan 2025 16:44:25 +0000 (17:44 +0100)
committerOleg Drokin <green@whamcloud.com>
Thu, 12 Jun 2025 06:32:01 +0000 (06:32 +0000)
Add a per-nodemap capabilities mask, used in preference to the global
enable_cap_mask parameter if it is set.
The new nodemap property is named enable_cap_mask, and can be set
thanks to the new lctl command 'nodemap_set_cap'. It is possible to
specify capabilities in hex or with symbolic names, with '+' and '-'
prefixes to respectively add or remove corresponding capabilities.
We support defining 2 types of capabilities, either a "set" so that it
is possible to add capabilities, or a "mask" to reduce capabilities of
the client.
This per-nodemap capabilities mask is available on any nodemap
including the default nodemap.

A dynamic child nodemap is allowed to define only a subset of the
capabilities set on the parent, unless the child_raise_privileges
property has the 'caps' privilege.

sanity-sec test_51 is enhanced to exercise this new nodemap property.

Signed-off-by: Sebastien Buisson <sbuisson@ddn.com>
Change-Id: I1ed91c721d869d0596af9c2d7e07a2c411f2b7c2
Reviewed-on: https://review.whamcloud.com/c/fs/lustre-release/+/57938
Tested-by: jenkins <devops@whamcloud.com>
Tested-by: Maloo <maloo@whamcloud.com>
Reviewed-by: Marc Vef <mvef@whamcloud.com>
Reviewed-by: Andreas Dilger <adilger@whamcloud.com>
Reviewed-by: Oleg Drokin <green@whamcloud.com>
26 files changed:
libcfs/include/libcfs/Makefile.am
libcfs/include/libcfs/libcfs_caps.h [new file with mode: 0644]
libcfs/libcfs/debug.c
lustre/doc/Makefile.am
lustre/doc/lctl-nodemap-modify.8
lustre/doc/lctl-nodemap-set-cap.8 [new file with mode: 0644]
lustre/doc/lctl-nodemap_set_cap.8 [new file with mode: 0644]
lustre/doc/lctl.8
lustre/include/lustre_nodemap.h
lustre/include/uapi/linux/lustre/lustre_cfg.h
lustre/include/uapi/linux/lustre/lustre_disk.h
lustre/include/uapi/linux/lustre/lustre_idl.h
lustre/mdt/mdt_internal.h
lustre/mdt/mdt_lib.c
lustre/mdt/mdt_lproc.c
lustre/ptlrpc/nodemap_handler.c
lustre/ptlrpc/nodemap_internal.h
lustre/ptlrpc/nodemap_lproc.c
lustre/ptlrpc/nodemap_storage.c
lustre/ptlrpc/wiretest.c
lustre/tests/sanity-sec.sh
lustre/utils/lctl.c
lustre/utils/obd.c
lustre/utils/obdctl.h
lustre/utils/wirecheck.c
lustre/utils/wiretest.c

index 1471122..f0bc78f 100644 (file)
@@ -15,4 +15,5 @@ EXTRA_DIST = \
        libcfs.h \
        libcfs_debug.h \
        libcfs_fail.h \
-       libcfs_private.h
+       libcfs_private.h \
+       libcfs_caps.h
diff --git a/libcfs/include/libcfs/libcfs_caps.h b/libcfs/include/libcfs/libcfs_caps.h
new file mode 100644 (file)
index 0000000..b8b7a5b
--- /dev/null
@@ -0,0 +1,97 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+
+/*
+ * Copyright (c) 2025 Whamcloud
+ */
+
+/*
+ * This file is part of Lustre, http://www.lustre.org/
+ *
+ * Generic capabilities manipulation functions.
+ *
+ */
+
+#ifndef __LIBCFS_CAPS_H__
+#define __LIBCFS_CAPS_H__
+
+static inline const char *libcfs_cap2str(int cap)
+{
+       /* We don't allow using all capabilities, but the fields must exist.
+        * The supported capabilities are CAP_FS_SET and CAP_NFSD_SET, plus
+        * CAP_SYS_ADMIN for a bunch of HSM operations (that should be fixed).
+        */
+       static const char *const capability_names[] = {
+               "cap_chown",                    /*  0 */
+               "cap_dac_override",             /*  1 */
+               "cap_dac_read_search",          /*  2 */
+               "cap_fowner",                   /*  3 */
+               "cap_fsetid",                   /*  4 */
+               NULL,                           /*  5 */
+               NULL,                           /*  6 */
+               NULL,                           /*  7 */
+               NULL,                           /*  8 */
+               "cap_linux_immutable",          /*  9 */
+               NULL,                           /* 10 */
+               NULL,                           /* 11 */
+               NULL,                           /* 12 */
+               NULL,                           /* 13 */
+               NULL,                           /* 14 */
+               NULL,                           /* 15 */
+               NULL,                           /* 16 */
+               NULL,                           /* 17 */
+               NULL,                           /* 18 */
+               NULL,                           /* 19 */
+               NULL,                           /* 20 */
+               /* we should use more precise capabilities than this */
+               "cap_sys_admin",                /* 21 */
+               NULL,                           /* 22 */
+               NULL,                           /* 23 */
+               "cap_sys_resource",             /* 24 */
+               NULL,                           /* 25 */
+               NULL,                           /* 26 */
+               "cap_mknod",                    /* 27 */
+               NULL,                           /* 28 */
+               NULL,                           /* 29 */
+               NULL,                           /* 30 */
+               NULL,                           /* 31 */
+               "cap_mac_override",             /* 32 */
+       };
+
+       if (cap >= ARRAY_SIZE(capability_names))
+               return NULL;
+
+       return capability_names[cap];
+}
+
+/* convert a capability into an integer to print or manage more easily */
+static inline u64 libcfs_cap2num(kernel_cap_t cap)
+{
+#ifdef CAP_FOR_EACH_U32
+       /* kernels before v6.2-13111-gf122a08b197d had a more complex
+        * kernel_cap_t structure with an array of __u32 values, but this
+        * was then fixed to have a single __u64 value.  There are accessor
+        * functions for the old kernel_cap_t but since that is now dead code
+        * it isn't worthwhile to jump through hoops for compatibility for it.
+        */
+       return ((u64)cap.cap[1] << 32) | cap.cap[0];
+#else
+       return cap.val;
+#endif
+}
+
+/* convert an integer into a capabilityt */
+static inline kernel_cap_t libcfs_num2cap(u64 num)
+{
+       kernel_cap_t cap;
+
+#ifdef CAP_FOR_EACH_U32
+       cap.cap[0] = num;
+       cap.cap[1] = (num >> 32);
+#else
+       cap.val = num;
+#endif
+
+       return cap;
+}
+
+#endif
index 1b8f28f..1be3f75 100644 (file)
@@ -307,7 +307,7 @@ int cfs_mask2str(char *str, int size, u64 mask, const char *(*bit2str)(int bit),
                str[len++] = '\n';
        if (len < size)
                str[len] = '\0';
-       else
+       else if (size)
                str[size - 1] = '\0';
 
        return len;
index aca6b29..1470328 100644 (file)
@@ -143,6 +143,8 @@ SERVER_MANFILES =                           \
        lctl-nodemap_info.8                     \
        lctl-nodemap-modify.8                   \
        lctl-nodemap_modify.8                   \
+       lctl-nodemap-set-cap.8                  \
+       lctl-nodemap_set_cap.8                  \
        lctl-nodemap-set-fileset.8              \
        lctl-nodemap_set_fileset.8              \
        lctl-nodemap-set-sepol.8                \
index 7bf4ab9..ae788d9 100644 (file)
@@ -113,6 +113,8 @@ separated) are the nodemap properties names that support privilege raise:
 .br
 - child_raise_privs
 .br
+- caps
+.br
 It is also possible to specify any roles accepted by the
 .B rbac
 property (see below).
diff --git a/lustre/doc/lctl-nodemap-set-cap.8 b/lustre/doc/lctl-nodemap-set-cap.8
new file mode 100644 (file)
index 0000000..8ba889b
--- /dev/null
@@ -0,0 +1,89 @@
+.TH LCTL-NODEMAP_SET_CAP 8 2025-05-27 Lustre "Lustre Configuration Utilities"
+.SH NAME
+lctl-nodemap_set_cap \- set user capabilities
+.SH SYNOPSIS
+.SY "lctl nodemap_set_cap"
+.BI --name " NODEMAP"
+.BI --caps " CAPABILITIES"
+.BI --type " {mask|set|off}"
+.YS
+.SH DESCRIPTION
+.B nodemap_set_cap
+defines capabilities for regular users on the specified
+.IR NODEMAP ,
+as described by
+.IR CAPABILITIES .
+The
+.I CAPABILITIES
+are a mask if the type is
+.B mask
+or a 'set' if type is
+.BR set .
+.SH OPTIONS
+.TP
+.BI --name " NODEMAP"
+The name of the nodemap to define capabilities for.
+.TP
+.BI --caps " CAPABILITIES"
+is the capabilities to apply.
+.TP
+.BI --type " {mask|set|off}"
+is the desired type for capabilities:
+.B mask
+for a capability mask,
+.B set
+to set user capabilities to the specified value,
+.B off
+to disable capabilities filtering.
+.SH EXAMPLES
+Define a capability mask as "cap_chown,cap_dac_read_search" on nodemap 'nm1':
+.EX
+.B # lctl nodemap_set_cap --name nm1 \
+--caps cap_chown,cap_dac_read_search --type mask
+.EE
+.PP
+Add "cap_fowner" to the capability mask on nodemap 'nm1':
+.EX
+.B # lctl nodemap_set_cap --name nm1 \
+--caps +cap_fowner --type mask
+.EE
+.PP
+Remove all capabilities users might have on nodemap 'nm1':
+.EX
+.B # lctl nodemap_set_cap --name nm1 \
+--caps 0 --type mask
+.EE
+.PP
+Set capabilities to "cap_linux_immutable,cap_sys_resource" for regular users on
+nodemap 'nm2':
+.EX
+.B # lctl nodemap_set_cap --name nm2 \
+--caps cap_linux_immutable,cap_sys_resource --type set
+.EE
+.PP
+Add "cap_fsetid" to the capabilities for regular users on nodemap 'nm2':
+.EX
+.B # lctl nodemap_set_cap --name nm2 \
+--caps +cap_fsetid --type set
+.EE
+.PP
+Disable capabilities filtering for regular users on nodemap 'nm2':
+.EX
+.B # lctl nodemap_set_cap --name nm2 --type off
+.EE
+.SH AVAILABILITY
+.B lctl nodemap_set_cap
+is part of the
+.BR lustre (7)
+filesystem package since release 2.17.0
+.\" Added in commit v2.16.99~
+.SH SEE ALSO
+.BR lustre (7),
+.BR lctl-nodemap-activate (8),
+.BR lctl-nodemap-add (8),
+.BR lctl-nodemap-add-idmap (8),
+.BR lctl-nodemap-add-range (8),
+.BR lctl-nodemap-del (8),
+.BR lctl-nodemap-del-idmap (8),
+.BR lctl-nodemap-del-range (8),
+.BR lctl-nodemap-modify (8)
diff --git a/lustre/doc/lctl-nodemap_set_cap.8 b/lustre/doc/lctl-nodemap_set_cap.8
new file mode 100644 (file)
index 0000000..88b22ea
--- /dev/null
@@ -0,0 +1 @@
+.so man8/lctl-nodemap-set-cap.8
index 9f2b6c4..a492644 100644 (file)
@@ -1,4 +1,4 @@
-.TH LCTL 8 2024-08-29 Lustre "Lustre Configuration Utilities"
+.TH LCTL 8 2025-01-31 Lustre "Lustre Configuration Utilities"
 .SH NAME
 lctl \- Lustre filesystem administrator configuration tool
 .SH SYNOPSIS
@@ -235,6 +235,9 @@ Remove a UID/GID/PROJID offset from a nodemap.
 .TP
 .BR lctl-nodemap-set-sepol (8)
 Set SELinux policy info on a nodemap.
+.TP
+.BR lctl-nodemap-set-capabilities (8)
+Set user capabilities on a nodemap.
 .SS Configuration logs
 .TP
 .BI clear_conf " DEVICE" \fR| FSNAME
@@ -427,13 +430,14 @@ filesystem package since release 0.5.0
 .BR lctl-nodemap-activate (8),
 .BR lctl-nodemap-add (8),
 .BR lctl-nodemap-add-idmap (8),
+.BR lctl-nodemap-add-offset (8),
 .BR lctl-nodemap-add-range (8),
 .BR lctl-nodemap-del (8),
 .BR lctl-nodemap-del-idmap (8),
+.BR lctl-nodemap-del-offset (8),
 .BR lctl-nodemap-del-range (8),
 .BR lctl-nodemap-modify (8),
-.BR lctl-nodemap-add-offset (8),
-.BR lctl-nodemap-del-offset (8),
+.BR lctl-nodemap-set-capabilities (8),
 .BR lctl-pcc (8),
 .BR lctl-replace-nids (8),
 .BR lctl-set_param (8),
index 02118a6..c986e57 100644 (file)
@@ -38,6 +38,15 @@ static const struct nodemap_rbac_name {
        { NODEMAP_RBAC_LOCAL_ADMIN,     "local_admin"   },
 };
 
+static const struct nodemap_captype_name {
+       enum nodemap_cap_type ncn_type;
+       const char           *ncn_name;
+} nodemap_captype_names[] = {
+       { NODEMAP_CAP_OFF,      "off"   },
+       { NODEMAP_CAP_MASK,     "mask"  },
+       { NODEMAP_CAP_SET,      "set"   },
+};
+
 struct nodemap_pde {
        char                     npe_name[LUSTRE_NODEMAP_NAME_LENGTH + 1];
        struct dentry           *npe_debugfs_entry;
@@ -55,6 +64,7 @@ static const struct nodemap_priv_name {
        { NODEMAP_RAISE_PRIV_RO,                "readonly_mount"        },
        /* NODEMAP_RAISE_PRIV_RBAC uses the rbac roles directly */
        { NODEMAP_RAISE_PRIV_FORBID_ENC,        "forbid_encryption"     },
+       { NODEMAP_RAISE_PRIV_CAPS,              "caps"  },
 };
 
 /** The nodemap id 0 will be the default nodemap. It will have a configuration
@@ -82,6 +92,8 @@ struct lu_nodemap {
        enum nodemap_raise_privs nmf_raise_privs;
        /* bitmap for rbac raise, enum nodemap_rbac_roles */
        enum nodemap_rbac_roles nmf_rbac_raise;
+       /* bitmap for capabilities type */
+       enum nodemap_cap_type    nmf_caps_type;
        /* unique ID set by MGS */
        unsigned int             nm_id;
        /* nodemap ref counter */
@@ -146,6 +158,8 @@ struct lu_nodemap {
        struct list_head         nm_parent_entry;
        /* link to parent nodemap */
        struct lu_nodemap       *nm_parent_nm;
+       /* user capabilities */
+       kernel_cap_t             nm_capabilities;
 };
 
 /* Store handles to local MGC storage to save config locally. In future
@@ -198,6 +212,7 @@ int nodemap_set_fileset(const char *name, const char *fileset, bool checkperm,
 char *nodemap_get_fileset(const struct lu_nodemap *nodemap);
 int nodemap_set_sepol(const char *name, const char *sepol, bool checkperm);
 const char *nodemap_get_sepol(const struct lu_nodemap *nodemap);
+int nodemap_set_capabilities(const char *nodemap_name, char *caps);
 __u32 nodemap_map_id(struct lu_nodemap *nodemap,
                     enum nodemap_id_type id_type,
                     enum nodemap_tree_type tree_type, __u32 id);
index 2b1b9cb..7802326 100644 (file)
@@ -128,6 +128,7 @@ enum lcfg_command_type {
        LCFG_NODEMAP_RBAC         = 0x00ce05f, /**< rbac */
        LCFG_NODEMAP_DENY_MOUNT   = 0x00ce060, /**< deny mount */
        LCFG_NODEMAP_RAISE_PRIVS        = 0x00ce061, /**< sub-nm raise privs */
+       LCFG_NODEMAP_SET_CAPS     = 0x00ce063, /**< user capabilities */
 };
 
 struct lustre_cfg_bufs {
index 253686d..4f111d8 100644 (file)
@@ -349,6 +349,16 @@ struct nodemap_fileset_rec {
        __u16   nfr_padding1;           /* zeroed since 2.16 (always) */
 };
 
+struct nodemap_user_capabilities_rec {
+       __u64   nucr_caps;
+       __u8    nucr_type;              /* enum nodemap_cap_type */
+       __u8    nucr_padding1;          /* zeroed since 2.16.51 (always) */
+       __u16   nucr_padding2;          /* zeroed since 2.16.51 (always) */
+       __u32   nucr_padding3;          /* zeroed since 2.16.51 (always) */
+       __u64   nucr_padding4;          /* zeroed since 2.16.51 (always) */
+       __u64   nucr_padding5;          /* zeroed since 2.16.51 (always) */
+};
+
 union nodemap_rec {
        struct nodemap_cluster_rec ncr;
        struct nodemap_range_rec nrr;
@@ -358,6 +368,7 @@ union nodemap_rec {
        struct nodemap_cluster_roles_rec ncrr;
        struct nodemap_offset_rec nor;
        struct nodemap_fileset_rec nfr;
+       struct nodemap_user_capabilities_rec nucr;
 };
 
 /* sub-keys for records of type NODEMAP_CLUSTER_IDX */
@@ -365,6 +376,7 @@ enum nodemap_cluster_rec_subid {
        NODEMAP_CLUSTER_REC = 0,   /* nodemap_cluster_rec */
        NODEMAP_CLUSTER_ROLES = 1, /* nodemap_cluster_roles_rec */
        NODEMAP_CLUSTER_OFFSET = 2, /* UID/GID/PROJID offset for a nm cluster */
+       NODEMAP_CLUSTER_CAPS = 3, /* User caps, nodemap_capabilities_rec */
        /*
         * A fileset may not fit in a single nodemap_fileset_rec and uses at max
         * 256 fragments. The first subid (512) is currently unused and reserved
index ef4bc35..f4c89c2 100644 (file)
@@ -3909,16 +3909,25 @@ enum nodemap_raise_privs {
        NODEMAP_RAISE_PRIV_RO           = 0x00000010,
        NODEMAP_RAISE_PRIV_RBAC         = 0x00000020,
        NODEMAP_RAISE_PRIV_FORBID_ENC   = 0x00000040,
+       NODEMAP_RAISE_PRIV_CAPS         = 0x00000080,
        NODEMAP_RAISE_PRIV_NONE = (__u32)~(NODEMAP_RAISE_PRIV_RAISE     |
                                           NODEMAP_RAISE_PRIV_ADMIN     |
                                           NODEMAP_RAISE_PRIV_TRUSTED   |
                                           NODEMAP_RAISE_PRIV_DENY_UNKN |
                                           NODEMAP_RAISE_PRIV_RO        |
                                           NODEMAP_RAISE_PRIV_RBAC      |
-                                          NODEMAP_RAISE_PRIV_FORBID_ENC),
+                                          NODEMAP_RAISE_PRIV_FORBID_ENC|
+                                          NODEMAP_RAISE_PRIV_CAPS),
        NODEMAP_RAISE_PRIV_ALL  = 0xFFFFFFFF, /* future privs RAISED by def */
 };
 
+enum nodemap_cap_type {
+       NODEMAP_CAP_OFF         = 0,
+       NODEMAP_CAP_MASK        = 1,
+       NODEMAP_CAP_SET         = 2,
+};
+
+
 /*
  * rawobj stuff for GSS
  */
index b7ce7e2..c3801ae 100644 (file)
@@ -1471,37 +1471,6 @@ static inline bool mdt_changelog_allow(struct mdt_thread_info *info)
        return is_admin;
 }
 
-/* convert a capability into an integer to print or manage more easily */
-static inline u64 mdt_cap2num(kernel_cap_t cap)
-{
-#ifdef CAP_FOR_EACH_U32
-       /* kernels before v6.2-13111-gf122a08b197d had a more complex
-        * kernel_cap_t structure with an array of __u32 values, but this
-        * was then fixed to have a single __u64 value.  There are accessor
-        * functions for the old kernel_cap_t but since that is now dead code
-        * it isn't worthwhile to jump through hoops for compatibility for it.
-        */
-       return ((u64)cap.cap[1] << 32) | cap.cap[0];
-#else
-       return cap.val;
-#endif
-}
-
-/* convert an integer into a capabilityt */
-static inline kernel_cap_t mdt_num2cap(u64 num)
-{
-       kernel_cap_t cap;
-
-#ifdef CAP_FOR_EACH_U32
-       cap.cap[0] = num;
-       cap.cap[1] = (num >> 32);
-#else
-       cap.val = num;
-#endif
-
-       return cap;
-}
-
 /* We forbid operations from encryption-unaware clients if they try to
  * manipulate encrypted files/directories.
  */
index 18ef1c0..9621568 100644 (file)
@@ -358,7 +358,15 @@ static int new_init_ucred(struct mdt_thread_info *info, ucred_init_type_t type,
        mdt_root_squash(info, &peernid);
 
        if (!is_local_root(ucred->uc_fsuid, nodemap)) {
-               if (!cap_issubset(ucred->uc_cap, mdt->mdt_enable_cap_mask))
+               kernel_cap_t caps;
+               bool from_nodemap;
+
+               from_nodemap = nodemap &&
+                       nodemap->nmf_caps_type != NODEMAP_CAP_OFF;
+               caps = from_nodemap ? nodemap->nm_capabilities :
+                       mdt->mdt_enable_cap_mask;
+
+               if (!cap_issubset(ucred->uc_cap, caps))
                        CDEBUG(D_SEC, "%s: drop capabilities %llx for NID %s\n",
                               mdt_obd_name(mdt),
 #ifdef CAP_FOR_EACH_U32
@@ -368,8 +376,10 @@ static int new_init_ucred(struct mdt_thread_info *info, ucred_init_type_t type,
                               ucred->uc_cap.val,
 #endif
                               libcfs_nidstr(&mdt_info_req(info)->rq_peer.nid));
-               ucred->uc_cap = cap_intersect(ucred->uc_cap,
-                                             mdt->mdt_enable_cap_mask);
+               if (!from_nodemap || nodemap->nmf_caps_type == NODEMAP_CAP_MASK)
+                       ucred->uc_cap = cap_intersect(ucred->uc_cap, caps);
+               else
+                       ucred->uc_cap = caps;
        }
 
        /* Thanks to Kerberos, Lustre does not have to trust clients anymore,
@@ -577,7 +587,15 @@ static int old_init_ucred_common(struct mdt_thread_info *info,
                        &mdt_info_req(info)->rq_peer.nid);
 
        if (!is_local_root(uc->uc_fsuid, nodemap)) {
-               if (!cap_issubset(uc->uc_cap, mdt->mdt_enable_cap_mask))
+               kernel_cap_t caps;
+               bool from_nodemap;
+
+               from_nodemap = nodemap &&
+                       nodemap->nmf_caps_type != NODEMAP_CAP_OFF;
+               caps = from_nodemap ? nodemap->nm_capabilities :
+                                     mdt->mdt_enable_cap_mask;
+
+               if (!cap_issubset(uc->uc_cap, caps))
                        CDEBUG(D_SEC, "%s: drop capabilities %llx for NID %s\n",
                               mdt_obd_name(mdt),
 #ifdef CAP_FOR_EACH_U32
@@ -586,8 +604,10 @@ static int old_init_ucred_common(struct mdt_thread_info *info,
                               uc->uc_cap.val,
 #endif
                               libcfs_nidstr(&mdt_info_req(info)->rq_peer.nid));
-               uc->uc_cap = cap_intersect(uc->uc_cap,
-                                          mdt->mdt_enable_cap_mask);
+               if (!from_nodemap || nodemap->nmf_caps_type == NODEMAP_CAP_MASK)
+                       uc->uc_cap = cap_intersect(uc->uc_cap, caps);
+               else
+                       uc->uc_cap = caps;
        }
 
        /* Thanks to Kerberos, Lustre does not have to trust clients anymore,
index c83f449..f77a5e2 100644 (file)
@@ -38,6 +38,7 @@
 #include <lprocfs_status.h>
 #include "mdt_internal.h"
 #include <obd_cksum.h>
+#include <libcfs/libcfs_caps.h>
 
 /**
  * The rename stats output would be YAML formats, like
@@ -650,64 +651,15 @@ mdt_nosquash_nids_seq_write(struct file *file, const char __user *buffer,
 }
 LPROC_SEQ_FOPS(mdt_nosquash_nids);
 
-static const char *mdt_cap2str(int cap)
-{
-       /* We don't allow using all capabilities, but the fields must exist.
-        * The supported capabilities are CAP_FS_SET and CAP_NFSD_SET, plus
-        * CAP_SYS_ADMIN for a bunch of HSM operations (that should be fixed).
-        */
-       static const char *const capability_names[] = {
-               "cap_chown",                    /*  0 */
-               "cap_dac_override",             /*  1 */
-               "cap_dac_read_search",          /*  2 */
-               "cap_fowner",                   /*  3 */
-               "cap_fsetid",                   /*  4 */
-               NULL,                           /*  5 */
-               NULL,                           /*  6 */
-               NULL,                           /*  7 */
-               NULL,                           /*  8 */
-               "cap_linux_immutable",          /*  9 */
-               NULL,                           /* 10 */
-               NULL,                           /* 11 */
-               NULL,                           /* 12 */
-               NULL,                           /* 13 */
-               NULL,                           /* 14 */
-               NULL,                           /* 15 */
-               NULL,                           /* 16 */
-               NULL,                           /* 17 */
-               NULL,                           /* 18 */
-               NULL,                           /* 19 */
-               NULL,                           /* 20 */
-               /* we should use more precise capabilities than this */
-               "cap_sys_admin",                /* 21 */
-               NULL,                           /* 22 */
-               NULL,                           /* 23 */
-               "cap_sys_resource",             /* 24 */
-               NULL,                           /* 25 */
-               NULL,                           /* 26 */
-               "cap_mknod",                    /* 27 */
-               NULL,                           /* 28 */
-               NULL,                           /* 29 */
-               NULL,                           /* 30 */
-               NULL,                           /* 31 */
-               "cap_mac_override",             /* 32 */
-       };
-
-       if (cap >= ARRAY_SIZE(capability_names))
-               return NULL;
-
-       return capability_names[cap];
-}
-
 static ssize_t enable_cap_mask_show(struct kobject *kobj,
                                    struct attribute *attr, char *buf)
 {
        struct obd_device *obd = container_of(kobj, struct obd_device,
                                              obd_kset.kobj);
        struct mdt_device *mdt = mdt_dev(obd->obd_lu_dev);
-       u64 mask = mdt_cap2num(mdt->mdt_enable_cap_mask);
+       u64 mask = libcfs_cap2num(mdt->mdt_enable_cap_mask);
 
-       return cfs_mask2str(buf, PAGE_SIZE, mask, mdt_cap2str, ',');
+       return cfs_mask2str(buf, PAGE_SIZE, mask, libcfs_cap2str, ',');
 }
 
 static ssize_t enable_cap_mask_store(struct kobject *kobj,
@@ -723,10 +675,10 @@ static ssize_t enable_cap_mask_store(struct kobject *kobj,
 
        rc = kstrtoull(buffer, 0, &val);
        if (rc == -EINVAL) {
-               u64 cap = mdt_cap2num(mdt->mdt_enable_cap_mask);
+               u64 cap = libcfs_cap2num(mdt->mdt_enable_cap_mask);
 
                /* the "allmask" is filtered by allowed_mask below */
-               rc = cfs_str2mask(buffer, mdt_cap2str, &cap, 0, ~0ULL, 0);
+               rc = cfs_str2mask(buffer, libcfs_cap2str, &cap, 0, ~0ULL, 0);
                val = cap;
        }
        if (rc)
@@ -738,7 +690,8 @@ static ssize_t enable_cap_mask_store(struct kobject *kobj,
                cap_raise(allowed_cap, CAP_SYS_RESOURCE);
        }
 
-       mdt->mdt_enable_cap_mask = cap_intersect(mdt_num2cap(val), allowed_cap);
+       mdt->mdt_enable_cap_mask = cap_intersect(libcfs_num2cap(val),
+                                                allowed_cap);
 
        return count;
 }
index 897d595..3bf0a20 100644 (file)
@@ -15,6 +15,7 @@
 #include <lustre_net.h>
 #include <lustre_acl.h>
 #include <obd_class.h>
+#include <libcfs/libcfs_caps.h>
 
 #include "nodemap_internal.h"
 #include "ptlrpc_internal.h"
@@ -227,6 +228,7 @@ static bool allow_op_on_nm(struct lu_nodemap *nodemap)
  * - nmf_rbac
  * - nmf_rbac_raise
  * - nmf_forbid_encryption
+ * - nm_capabilities
  * If nmf_raise_privs grants corresponding privilege, any change on these
  * properties is permitted. Otherwise, only lowering privileges is possible,
  * which means:
@@ -237,6 +239,7 @@ static bool allow_op_on_nm(struct lu_nodemap *nodemap)
  * - nmf_rbac to fewer roles
  * - nmf_rbac_raise to fewer roles
  * - nmf_forbid_encryption from 1 (parent) to 0
+ * - nm_capabilities of child is a subset of parent's
  *
  * Return:
  * * %true             if the modification is allowed
@@ -247,6 +250,7 @@ static bool check_privs_for_op(struct lu_nodemap *nodemap,
        u32 prop_val = (u32)(0xffffffff & val);
        /* only relevant with priv == NODEMAP_RAISE_PRIV_RAISE */
        u32 rbac_raise = (u32)(val >> 32);
+       kernel_cap_t *newcaps;
 
        if (!allow_op_on_nm(nodemap))
                return false;
@@ -279,6 +283,10 @@ static bool check_privs_for_op(struct lu_nodemap *nodemap,
        case NODEMAP_RAISE_PRIV_FORBID_ENC:
                return (nodemap->nm_parent_nm->nmf_forbid_encryption ||
                        !prop_val);
+       case NODEMAP_RAISE_PRIV_CAPS:
+               newcaps = (kernel_cap_t *)&val;
+               return cap_issubset(*newcaps,
+                                   nodemap->nm_parent_nm->nm_capabilities);
        default:
                return true;
        }
@@ -1096,6 +1104,8 @@ static int nodemap_inherit_properties(struct lu_nodemap *dst,
                dst->nm_offset_limit_projid = 0;
                dst->nm_prim_fileset = NULL;
                dst->nm_prim_fileset_size = 0;
+               dst->nm_capabilities = CAP_EMPTY_SET;
+               dst->nmf_caps_type = NODEMAP_CAP_OFF;
        } else {
                dst->nmf_trust_client_ids = src->nmf_trust_client_ids;
                dst->nmf_allow_root_access = src->nmf_allow_root_access;
@@ -1138,6 +1148,8 @@ static int nodemap_inherit_properties(struct lu_nodemap *dst,
                        dst->nm_prim_fileset = NULL;
                        dst->nm_prim_fileset_size = 0;
                }
+               dst->nm_capabilities = src->nm_capabilities;
+               dst->nmf_caps_type = src->nmf_caps_type;
        }
 
 out:
@@ -1674,6 +1686,102 @@ const char *nodemap_get_sepol(const struct lu_nodemap *nodemap)
 EXPORT_SYMBOL(nodemap_get_sepol);
 
 /**
+ * nodemap_set_capabilities() - Define user capabilities on nodemap
+ * @name: name of nodemap
+ * @buffer: capabilities to set
+ *
+ * It is possible to specify capabilities in hex or with symbolic names, with
+ * '+' and '-' prefixes to respectively add or remove corresponding
+ * capabilities. If buffer starts with "set:", the capabilities are set to the
+ * specified ones, making it possible to add capabilities. If buffer starts with
+ * "mask:", the capabilities are filtered through the specified mask. If buffer
+ * is "off", the enable_cap_mask property is cleared.
+ *
+ * Return:
+ * * %0 on success
+ */
+int nodemap_set_capabilities(const char *name, char *buffer)
+{
+       static kernel_cap_t allowed_cap = CAP_EMPTY_SET;
+       struct lu_nodemap *nodemap = NULL;
+       enum nodemap_cap_type type;
+       unsigned long long caps;
+       kernel_cap_t newcaps;
+       bool cap_was_clear;
+       u64 *p_newcaps;
+       u64 cap_tmp;
+       char *caps_str;
+       int i, rc;
+
+       caps_str = strchr(buffer, ':');
+       if (!caps_str)
+               GOTO(out, rc = -EINVAL);
+       *caps_str = '\0';
+       caps_str++;
+
+       for (i = 0; i < ARRAY_SIZE(nodemap_captype_names); i++) {
+               if (strcmp(buffer, nodemap_captype_names[i].ncn_name) == 0) {
+                       type = nodemap_captype_names[i].ncn_type;
+                       break;
+               }
+       }
+       if (i == ARRAY_SIZE(nodemap_captype_names))
+               GOTO(out, rc = -EINVAL);
+
+       mutex_lock(&active_config_lock);
+       nodemap = nodemap_lookup(name);
+       if (IS_ERR(nodemap)) {
+               mutex_unlock(&active_config_lock);
+               GOTO(out, rc = PTR_ERR(nodemap));
+       }
+
+       rc = kstrtoull(caps_str, 0, &caps);
+       if (rc == -EINVAL) {
+               cap_tmp = libcfs_cap2num(nodemap->nm_capabilities);
+               /* if type is different, capabilities are going to be reset */
+               if (type != nodemap->nmf_caps_type)
+                       cap_tmp = libcfs_cap2num(CAP_EMPTY_SET);
+
+               /* the "allmask" is filtered by allowed_cap below */
+               rc = cfs_str2mask(caps_str, libcfs_cap2str, &cap_tmp, 0,
+                                 ~0ULL, 0);
+               caps = cap_tmp;
+       }
+       if (rc)
+               GOTO(out_putref, rc);
+
+       /* All of the capabilities that we currently allow/check */
+       if (unlikely(cap_isclear(allowed_cap))) {
+               allowed_cap = CAP_FS_SET;
+               cap_raise(allowed_cap, CAP_SYS_RESOURCE);
+       }
+
+       newcaps = cap_intersect(libcfs_num2cap(caps), allowed_cap);
+       p_newcaps = (u64 *)&newcaps;
+       if (!check_privs_for_op(nodemap, NODEMAP_RAISE_PRIV_CAPS, *p_newcaps))
+               GOTO(out_putref, rc = -EPERM);
+
+       cap_was_clear = cap_isclear(nodemap->nm_capabilities);
+       nodemap->nm_capabilities = newcaps;
+       nodemap->nmf_caps_type = type;
+
+       if (cap_isclear(nodemap->nm_capabilities))
+               rc = nodemap_idx_capabilities_del(nodemap);
+       else if (cap_was_clear)
+               rc = nodemap_idx_capabilities_add(nodemap);
+       else
+               rc = nodemap_idx_capabilities_update(nodemap);
+
+       nm_member_revoke_locks(nodemap);
+
+out_putref:
+       mutex_unlock(&active_config_lock);
+       nodemap_putref(nodemap);
+out:
+       return rc;
+}
+
+/**
  * nodemap_create() - Nodemap constructor
  * @name: name of nodemap
  * @config: pointer to struct nodemap_config
@@ -3277,6 +3385,9 @@ static int cfg_nodemap_cmd(enum lcfg_command_type cmd, const char *nodemap_name,
        case LCFG_NODEMAP_SET_SEPOL:
                rc = nodemap_set_sepol(nodemap_name, param, true);
                break;
+       case LCFG_NODEMAP_SET_CAPS:
+               rc = nodemap_set_capabilities(nodemap_name, param);
+               break;
        default:
                rc = -EINVAL;
        }
@@ -3420,6 +3531,7 @@ int server_iocontrol_nodemap(struct obd_device *obd,
        case LCFG_NODEMAP_DEL_PROJIDMAP:
        case LCFG_NODEMAP_SET_FILESET:
        case LCFG_NODEMAP_SET_SEPOL:
+       case LCFG_NODEMAP_SET_CAPS:
                if (lcfg->lcfg_bufcount != 3)
                        GOTO(out_lcfg, rc = -EINVAL);
                nodemap_name = lustre_cfg_string(lcfg, 1);
index 2abb180..12d1995 100644 (file)
@@ -196,6 +196,9 @@ int nodemap_idx_fileset_update(const struct lu_nodemap *nodemap,
 int nodemap_idx_fileset_del(const struct lu_nodemap *nodemap,
                            const char *fileset, unsigned int fileset_id);
 int nodemap_idx_fileset_clear(const struct lu_nodemap *nodemap);
+int nodemap_idx_capabilities_add(const struct lu_nodemap *nodemap);
+int nodemap_idx_capabilities_update(const struct lu_nodemap *nodemap);
+int nodemap_idx_capabilities_del(const struct lu_nodemap *nodemap);
 int nodemap_idx_idmap_add(const struct lu_nodemap *nodemap,
                          enum nodemap_id_type id_type,
                          const __u32 map[2]);
index 63552c2..b7493bd 100644 (file)
@@ -15,6 +15,7 @@
 #include <lustre_net.h>
 #include <lustre_export.h>
 #include <obd_class.h>
+#include <libcfs/libcfs_caps.h>
 #include "nodemap_internal.h"
 
 static LIST_HEAD(nodemap_pde_list);
@@ -144,6 +145,63 @@ static int nodemap_offset_seq_show(struct seq_file *m, void *data)
 }
 
 /**
+ * nodemap_capabilities_seq_show() - Reads and prints capabilities definitions.
+ * @m: seq file in proc fs
+ * @unused: unused
+ *
+ * Return:
+ * * %0 on success
+ */
+static int nodemap_capabilities_seq_show(struct seq_file *m, void *unused)
+{
+       struct lu_nodemap *nodemap;
+       const char *type;
+       char *caps;
+       u64 val;
+       int i, rc = 0;
+
+       mutex_lock(&active_config_lock);
+       nodemap = nodemap_lookup(m->private);
+       mutex_unlock(&active_config_lock);
+       if (IS_ERR(nodemap)) {
+               rc = PTR_ERR(nodemap);
+               CERROR("%s: nodemap not found: rc = %d\n",
+                      (char *)m->private, rc);
+               return rc;
+       }
+
+       type = nodemap_captype_names[0].ncn_name;
+       for (i = 0; i < ARRAY_SIZE(nodemap_captype_names); i++) {
+               if (nodemap_captype_names[i].ncn_type ==
+                   nodemap->nmf_caps_type) {
+                       type = nodemap_captype_names[i].ncn_name;
+                       break;
+               }
+       }
+       /* if not applicable, stop here */
+       if (nodemap->nmf_caps_type == NODEMAP_CAP_OFF) {
+               seq_printf(m, "%s\n", type);
+               goto out;
+       }
+
+       val = libcfs_cap2num(nodemap->nm_capabilities);
+       i = cfs_mask2str(NULL, 0, val, libcfs_cap2str, ',');
+       OBD_ALLOC(caps, i + 2);
+       if (!caps)
+               GOTO(out, rc = -ENOMEM);
+       cfs_mask2str(caps, i + 2, val, libcfs_cap2str, ',');
+
+       seq_printf(m, "type: %s\n", type);
+       seq_printf(m, "caps: %s", caps);
+
+       OBD_FREE(caps, i + 2);
+
+out:
+       nodemap_putref(nodemap);
+       return rc;
+}
+
+/**
  * Reads and prints the NID ranges for the given nodemap.
  *
  * \param      m               seq file in proc fs
@@ -974,6 +1032,7 @@ LDEBUGFS_SEQ_FOPS_RO(nodemap_squash_projid);
 LDEBUGFS_SEQ_FOPS_RO(nodemap_deny_unknown);
 LDEBUGFS_SEQ_FOPS_RO(nodemap_map_mode);
 LDEBUGFS_SEQ_FOPS_RO(nodemap_offset);
+LDEBUGFS_SEQ_FOPS_RO(nodemap_capabilities);
 LDEBUGFS_SEQ_FOPS_RO(nodemap_rbac);
 LDEBUGFS_SEQ_FOPS_RO(nodemap_audit_mode);
 LDEBUGFS_SEQ_FOPS_RO(nodemap_forbid_encryption);
@@ -1018,6 +1077,10 @@ static struct ldebugfs_vars lprocfs_nodemap_vars[] = {
                .fops           = &nodemap_deny_unknown_fops,
        },
        {
+               .name           = "enable_cap_mask",
+               .fops           = &nodemap_capabilities_fops,
+       },
+       {
                .name           = "exports",
                .fops           = &nodemap_exports_fops,
        },
@@ -1109,6 +1172,10 @@ static struct ldebugfs_vars lprocfs_default_nodemap_vars[] = {
                .fops           = &nodemap_deny_unknown_fops,
        },
        {
+               .name           = "enable_cap_mask",
+               .fops           = &nodemap_capabilities_fops,
+       },
+       {
                .name           = "exports",
                .fops           = &nodemap_exports_fops,
        },
index eeaa2f2..a4e06b5 100644 (file)
@@ -41,6 +41,7 @@
 #include <lustre_nodemap.h>
 #include <obd_class.h>
 #include <obd_support.h>
+#include <libcfs/libcfs_caps.h>
 #include "nodemap_internal.h"
 
 /* list of registered nodemap index files, except MGS */
@@ -145,6 +146,16 @@ static int nodemap_cluster_fileset_rec_init(union nodemap_rec *nr,
        return rc;
 }
 
+static void nodemap_capabilities_rec_init(union nodemap_rec *nr,
+                                         const struct lu_nodemap *nodemap)
+{
+       struct nodemap_user_capabilities_rec *nucr = &nr->nucr;
+
+       memset(nucr, 0, sizeof(struct nodemap_user_capabilities_rec));
+       nucr->nucr_caps = cpu_to_le64(libcfs_cap2num(nodemap->nm_capabilities));
+       nucr->nucr_type = nodemap->nmf_caps_type;
+}
+
 static void nodemap_idmap_key_init(struct nodemap_key *nk, unsigned int nm_id,
                                   enum nodemap_id_type id_type,
                                   u32 id_client)
@@ -567,6 +578,9 @@ static int nodemap_idx_cluster_add_update(const struct lu_nodemap *nodemap,
        case NODEMAP_CLUSTER_OFFSET:
                nodemap_offset_rec_init(&nr, nodemap);
                break;
+       case NODEMAP_CLUSTER_CAPS:
+               nodemap_capabilities_rec_init(&nr, nodemap);
+               break;
        default:
                CWARN("%s: unknown subtype %u\n", nodemap->nm_name, subid);
                GOTO(fini, rc = -EINVAL);
@@ -630,6 +644,11 @@ int nodemap_idx_nodemap_del(const struct lu_nodemap *nodemap)
        if (rc2 < 0 && rc2 != -ENOENT)
                rc = rc2;
 
+       nodemap_cluster_key_init(&nk, nodemap->nm_id, NODEMAP_CLUSTER_CAPS);
+       rc2 = nodemap_idx_delete(&env, nodemap_mgs_ncf->ncf_obj, &nk, NULL);
+       if (rc2 < 0 && rc2 != -ENOENT)
+               rc = rc2;
+
        root = nodemap->nm_fs_to_client_uidmap;
        rbtree_postorder_for_each_entry_safe(idmap, temp, &root,
                                             id_fs_to_client) {
@@ -1176,6 +1195,45 @@ int nodemap_idx_fileset_clear(const struct lu_nodemap *nodemap)
        return rc;
 }
 
+int nodemap_idx_capabilities_add(const struct lu_nodemap *nodemap)
+{
+       return nodemap_idx_cluster_add_update(nodemap, NULL, NM_ADD,
+                                             NODEMAP_CLUSTER_CAPS);
+}
+
+int nodemap_idx_capabilities_update(const struct lu_nodemap *nodemap)
+{
+       return nodemap_idx_cluster_add_update(nodemap, NULL, NM_UPDATE,
+                                             NODEMAP_CLUSTER_CAPS);
+}
+
+int nodemap_idx_capabilities_del(const struct lu_nodemap *nodemap)
+{
+       struct nodemap_key nk;
+       struct lu_env env;
+       int rc = 0;
+
+       ENTRY;
+
+       if (nodemap->nm_dyn)
+               return 0;
+
+       if (!nodemap_mgs()) {
+               CERROR("cannot add nodemap config to non-existing MGS.\n");
+               return -EINVAL;
+       }
+
+       rc = lu_env_init(&env, LCT_LOCAL);
+       if (rc != 0)
+               RETURN(rc);
+
+       nodemap_cluster_key_init(&nk, nodemap->nm_id, NODEMAP_CLUSTER_CAPS);
+       rc = nodemap_idx_delete(&env, nodemap_mgs_ncf->ncf_obj, &nk, NULL);
+
+       lu_env_fini(&env);
+       RETURN(rc);
+}
+
 int nodemap_idx_range_add(struct lu_nodemap *nodemap,
                          const struct lu_nid_range *range)
 {
@@ -1550,6 +1608,16 @@ static int nodemap_cluster_fileset_helper(struct lu_nodemap *nodemap,
        return -EINVAL;
 }
 
+static int nodemap_capabilities_helper(struct lu_nodemap *nodemap,
+                                      const union nodemap_rec *rec)
+{
+       nodemap->nm_capabilities =
+               libcfs_num2cap(le64_to_cpu(rec->nucr.nucr_caps));
+       nodemap->nmf_caps_type = rec->nucr.nucr_type;
+
+       return 0;
+}
+
 /**
  * Process a key/rec pair and modify the new configuration.
  *
@@ -1636,6 +1704,8 @@ static int nodemap_process_keyrec(struct nodemap_config *config,
                        rc = nodemap_add_offset_helper(
                                nodemap, le32_to_cpu(rec->nor.nor_start_uid),
                                le32_to_cpu(rec->nor.nor_limit_uid));
+               } else if (cluster_idx_key == NODEMAP_CLUSTER_CAPS) {
+                       rc = nodemap_capabilities_helper(nodemap, rec);
                } else if (cluster_idx_key >= NODEMAP_FILESET &&
                           cluster_idx_key <
                                   NODEMAP_FILESET +
@@ -1935,6 +2005,13 @@ nodemap_save_config_cache(const struct lu_env *env,
                if (rc2 < 0)
                        rc = rc2;
 
+               nodemap_cluster_key_init(&nk, nodemap->nm_id,
+                                        NODEMAP_CLUSTER_CAPS);
+               nodemap_capabilities_rec_init(&nr, nodemap);
+               rc2 = nodemap_idx_insert(env, o, &nk, &nr);
+               if (rc2 < 0)
+                       rc = rc2;
+
                down_read(&active_config->nmc_range_tree_lock);
                list_for_each_entry_safe(range, range_temp, &nodemap->nm_ranges,
                                         rn_list) {
index 02668ee..f1d2855 100644 (file)
@@ -6437,6 +6437,38 @@ void lustre_assert_wire_constants(void)
        LASSERTF((int)sizeof(((struct nodemap_fileset_rec *)0)->nfr_padding1) == 2, "found %lld\n",
                 (long long)(int)sizeof(((struct nodemap_fileset_rec *)0)->nfr_padding1));
 
+       /* Checks for struct nodemap_user_capabilities_rec */
+       LASSERTF((int)sizeof(struct nodemap_user_capabilities_rec) == 32, "found %lld\n",
+                (long long)(int)sizeof(struct nodemap_user_capabilities_rec));
+       LASSERTF((int)offsetof(struct nodemap_user_capabilities_rec, nucr_caps) == 0, "found %lld\n",
+                (long long)(int)offsetof(struct nodemap_user_capabilities_rec, nucr_caps));
+       LASSERTF((int)sizeof(((struct nodemap_user_capabilities_rec *)0)->nucr_caps) == 8, "found %lld\n",
+                (long long)(int)sizeof(((struct nodemap_user_capabilities_rec *)0)->nucr_caps));
+       LASSERTF((int)offsetof(struct nodemap_user_capabilities_rec, nucr_type) == 8, "found %lld\n",
+                (long long)(int)offsetof(struct nodemap_user_capabilities_rec, nucr_type));
+       LASSERTF((int)sizeof(((struct nodemap_user_capabilities_rec *)0)->nucr_type) == 1, "found %lld\n",
+                (long long)(int)sizeof(((struct nodemap_user_capabilities_rec *)0)->nucr_type));
+       LASSERTF((int)offsetof(struct nodemap_user_capabilities_rec, nucr_padding1) == 9, "found %lld\n",
+                (long long)(int)offsetof(struct nodemap_user_capabilities_rec, nucr_padding1));
+       LASSERTF((int)sizeof(((struct nodemap_user_capabilities_rec *)0)->nucr_padding1) == 1, "found %lld\n",
+                (long long)(int)sizeof(((struct nodemap_user_capabilities_rec *)0)->nucr_padding1));
+       LASSERTF((int)offsetof(struct nodemap_user_capabilities_rec, nucr_padding2) == 10, "found %lld\n",
+                (long long)(int)offsetof(struct nodemap_user_capabilities_rec, nucr_padding2));
+       LASSERTF((int)sizeof(((struct nodemap_user_capabilities_rec *)0)->nucr_padding2) == 2, "found %lld\n",
+                (long long)(int)sizeof(((struct nodemap_user_capabilities_rec *)0)->nucr_padding2));
+       LASSERTF((int)offsetof(struct nodemap_user_capabilities_rec, nucr_padding3) == 12, "found %lld\n",
+                (long long)(int)offsetof(struct nodemap_user_capabilities_rec, nucr_padding3));
+       LASSERTF((int)sizeof(((struct nodemap_user_capabilities_rec *)0)->nucr_padding3) == 4, "found %lld\n",
+                (long long)(int)sizeof(((struct nodemap_user_capabilities_rec *)0)->nucr_padding3));
+       LASSERTF((int)offsetof(struct nodemap_user_capabilities_rec, nucr_padding4) == 16, "found %lld\n",
+                (long long)(int)offsetof(struct nodemap_user_capabilities_rec, nucr_padding4));
+       LASSERTF((int)sizeof(((struct nodemap_user_capabilities_rec *)0)->nucr_padding4) == 8, "found %lld\n",
+                (long long)(int)sizeof(((struct nodemap_user_capabilities_rec *)0)->nucr_padding4));
+       LASSERTF((int)offsetof(struct nodemap_user_capabilities_rec, nucr_padding5) == 24, "found %lld\n",
+                (long long)(int)offsetof(struct nodemap_user_capabilities_rec, nucr_padding5));
+       LASSERTF((int)sizeof(((struct nodemap_user_capabilities_rec *)0)->nucr_padding5) == 8, "found %lld\n",
+                (long long)(int)sizeof(((struct nodemap_user_capabilities_rec *)0)->nucr_padding5));
+
        /* Checks for union nodemap_rec */
        LASSERTF((int)sizeof(union nodemap_rec) == 32, "found %lld\n",
                 (long long)(int)sizeof(union nodemap_rec));
@@ -6484,6 +6516,8 @@ void lustre_assert_wire_constants(void)
                 (long long)NODEMAP_CLUSTER_ROLES);
        LASSERTF(NODEMAP_CLUSTER_OFFSET == 2, "found %lld\n",
                 (long long)NODEMAP_CLUSTER_OFFSET);
+       LASSERTF(NODEMAP_CLUSTER_CAPS == 3, "found %lld\n",
+                (long long)NODEMAP_CLUSTER_CAPS);
        LASSERTF(NM_TYPE_MASK == 0x0fffffffUL, "found 0x%.8xUL\n",
                (unsigned)NM_TYPE_MASK);
        LASSERTF(NM_TYPE_SHIFT == 28, "found %lld\n",
@@ -6570,7 +6604,9 @@ void lustre_assert_wire_constants(void)
                 (unsigned)NODEMAP_RAISE_PRIV_RBAC);
        LASSERTF(NODEMAP_RAISE_PRIV_FORBID_ENC == 0x00000040UL, "found 0x%.8xUL\n",
                 (unsigned)NODEMAP_RAISE_PRIV_FORBID_ENC);
-       LASSERTF(NODEMAP_RAISE_PRIV_NONE == 0xffffff80UL, "found 0x%.8xUL\n",
+       LASSERTF(NODEMAP_RAISE_PRIV_CAPS == 0x00000080UL, "found 0x%.8xUL\n",
+                (unsigned)NODEMAP_RAISE_PRIV_CAPS);
+       LASSERTF(NODEMAP_RAISE_PRIV_NONE == 0xffffff00UL, "found 0x%.8xUL\n",
                 (unsigned)NODEMAP_RAISE_PRIV_NONE);
        LASSERTF(NODEMAP_RAISE_PRIV_ALL == 0xffffffffUL, "found 0x%.8xUL\n",
                 (unsigned)NODEMAP_RAISE_PRIV_ALL);
@@ -7150,6 +7186,8 @@ void lustre_assert_wire_constants(void)
                (unsigned int)LCFG_NODEMAP_DENY_MOUNT);
        LASSERTF(LCFG_NODEMAP_RAISE_PRIVS == 0x000ce061UL, "found 0x%.8xUL\n",
                 (unsigned)LCFG_NODEMAP_RAISE_PRIVS);
+       LASSERTF(LCFG_NODEMAP_SET_CAPS == 0x00ce063UL, "found 0x%.8xUL\n",
+                (unsigned)LCFG_NODEMAP_SET_CAPS);
 #endif /* HAVE_SERVER_SUPPORT */
        LASSERTF(PORTALS_CFG_TYPE == 1, "found %lld\n",
                 (long long)PORTALS_CFG_TYPE);
index 4c773b5..f6cb642 100755 (executable)
@@ -4931,6 +4931,8 @@ test_51() {
        mkdir $DIR/$tdir || error "mkdir $tdir"
        local mdts=$(comma_list $(mdts_nodes))
        local cap_param=mdt.*.enable_cap_mask
+       local nm_param=nodemap.default.enable_cap_mask
+       local val
 
        old_cap=($(do_nodes $mdts $LCTL get_param -n $cap_param 2>/dev/null))
        if [[ -n "$old_cap" ]]; then
@@ -4945,27 +4947,27 @@ test_51() {
                stack_trap "do_nodes $mdts $LCTL set_param $cap_param=$old_cap"
        fi
 
-       touch $DIR/$tdir/$tfile || error "touch $tfile"
+       touch $DIR/$tdir/$tfile || error "touch $tfile as root (1)"
        cp $(which chown) $DIR/$tdir || error "cp chown"
        $RUNAS_CMD -u $ID0 $DIR/$tdir/chown $ID0 $DIR/$tdir/$tfile &&
-               error "chown $tfile should fail"
+               error "chown $tfile should fail (1)"
        setcap 'CAP_CHOWN=ep' $DIR/$tdir/chown || error "setcap CAP_CHOWN"
        $RUNAS_CMD -u $ID0 $DIR/$tdir/chown $ID0 $DIR/$tdir/$tfile ||
-               error "chown $tfile"
-       rm $DIR/$tdir/$tfile || error "rm $tfile"
+               error "chown $tfile as $ID0 (1)"
+       rm $DIR/$tdir/$tfile || error "rm $tfile (1)"
 
-       touch $DIR/$tdir/$tfile || error "touch $tfile"
+       touch $DIR/$tdir/$tfile || error "touch $tfile as root (2)"
        cp $(which touch) $DIR/$tdir || error "cp touch"
        $RUNAS_CMD -u $ID0 $DIR/$tdir/touch $DIR/$tdir/$tfile &&
                error "touch should fail"
        setcap 'CAP_FOWNER=ep' $DIR/$tdir/touch || error "setcap CAP_FOWNER"
        $RUNAS_CMD -u $ID0 $DIR/$tdir/touch $DIR/$tdir/$tfile ||
                error "touch $tfile"
-       rm $DIR/$tdir/$tfile || error "rm $tfile"
+       rm $DIR/$tdir/$tfile || error "rm $tfile (2)"
 
        local cap
        for cap in "CAP_DAC_OVERRIDE" "CAP_DAC_READ_SEARCH"; do
-               touch $DIR/$tdir/$tfile || error "touch $tfile"
+               touch $DIR/$tdir/$tfile || error "touch $tfile as root (3)"
                chmod 600 $DIR/$tdir/$tfile || error "chmod $tfile"
                cp $(which cat) $DIR/$tdir || error "cp cat"
                $RUNAS_CMD -u $ID0 $DIR/$tdir/cat $DIR/$tdir/$tfile &&
@@ -4973,8 +4975,88 @@ test_51() {
                setcap $cap=ep $DIR/$tdir/cat || error "setcap $cap"
                $RUNAS_CMD -u $ID0 $DIR/$tdir/cat $DIR/$tdir/$tfile ||
                        error "cat $tfile"
-               rm $DIR/$tdir/$tfile || error "rm $tfile"
+               rm $DIR/$tdir/$tfile || error "rm $tfile (3)"
        done
+
+       if (( "$MDS1_VERSION" >= $(version_code 2.16.55) )); then
+               val=$(do_facet mgs $LCTL get_param -n $nm_param)
+               [[ "$val" == "off" ]] ||
+                       error "wrong default value $val for $nm_param"
+
+               do_facet mgs $LCTL nodemap_modify --name default \
+                       --property admin --value 1
+               do_facet mgs $LCTL nodemap_modify --name default \
+                       --property trusted --value 1
+               wait_nm_sync default trusted_nodemap
+
+               do_facet mgs $LCTL nodemap_activate 1
+               wait_nm_sync active 1
+               stack_trap cleanup_active EXIT
+               stack_trap "do_facet mgs $LCTL nodemap_modify --name default \
+                       --property admin --value 0" EXIT
+               stack_trap "do_facet mgs $LCTL nodemap_modify --name default \
+                       --property trusted --value 0" EXIT
+               stack_trap "do_facet mgs $LCTL nodemap_set_cap \
+                       --name default --type off" EXIT
+
+               # $DIR/$tdir/chown has CAP_CHOWN, so it should succeed with
+               # enable_cap_mask=off on nodemap
+               touch $DIR/$tdir/$tfile || error "touch $tfile as root (4)"
+               $RUNAS_CMD -u $ID0 $DIR/$tdir/chown $ID0 $DIR/$tdir/$tfile ||
+                       error "chown $tfile as $ID0 (2)"
+               rm $DIR/$tdir/$tfile || error "rm $tfile (4)"
+
+               do_facet mgs $LCTL nodemap_set_cap --name default \
+                  --type mask --caps cap_dac_read_search ||
+                       error "nodemap_set_cap failed (1)"
+               wait_nm_sync default enable_cap_mask
+
+               # $DIR/$tdir/chown should fail with
+               # enable_cap_mask=mask:cap_dac_read_search on nodemap
+               touch $DIR/$tdir/$tfile || error "touch $tfile as root (5)"
+               $RUNAS_CMD -u $ID0 $DIR/$tdir/chown $ID0 $DIR/$tdir/$tfile &&
+                       error "chown $tfile should fail (2)"
+               do_facet mgs $LCTL nodemap_set_cap --name default \
+                  --type mask --caps +cap_chown ||
+                       error "nodemap_set_cap failed (2)"
+               wait_nm_sync default enable_cap_mask
+               # $DIR/$tdir/chown should succeed with
+               # enable_cap_mask=mask:cap_chown,cap_dac_read_search
+               $RUNAS_CMD -u $ID0 $DIR/$tdir/chown $ID0 $DIR/$tdir/$tfile ||
+                       error "chown $tfile as $ID0 (3)"
+               rm $DIR/$tdir/$tfile || error "rm $tfile (5)"
+
+               # Test ability to raise caps on child nodemap
+               do_facet mgs $LCTL nodemap_modify --name default \
+                  --property child_raise_privileges --value none ||
+                       error "setting child_raise_privileges=none failed"
+               wait_nm_sync default child_raise_privileges
+               stack_trap "do_facet mgs $LCTL nodemap_modify --name default \
+                           --property child_raise_privileges --value none" EXIT
+               do_facet mds1 $LCTL nodemap_add -d -p default nm_51 ||
+                       error "cannot create nodemap nm_51 (1)"
+               stack_trap "do_facet mds1 $LCTL nodemap_del nm_51" EXIT
+               do_facet mds1 $LCTL nodemap_set_cap --name nm_51 \
+                  --type mask --caps +cap_fowner &&
+                       error "nodemap_set_cap +cap_fowner should fail"
+               do_facet mds1 $LCTL nodemap_set_cap --name nm_51 \
+                  --type mask --caps -cap_chown ||
+                       error "nodemap_set_cap -cap_chown failed"
+               do_facet mds1 $LCTL nodemap_set_cap --name nm_51 \
+                  --type mask --caps +cap_chown ||
+                       error "nodemap_set_cap +cap_chown failed"
+               do_facet mds1 $LCTL nodemap_del nm_51 ||
+                       error "cannot delete nodemap nm_51"
+               do_facet mgs $LCTL nodemap_modify --name default \
+                  --property child_raise_privileges --value caps ||
+                       error "setting child_raise_privileges=caps failed"
+               wait_nm_sync default child_raise_privileges
+               do_facet mds1 $LCTL nodemap_add -d -p default nm_51 ||
+                       error "cannot create nodemap nm_51 (2)"
+               do_facet mds1 $LCTL nodemap_set_cap --name nm_51 \
+                  --type mask --caps +cap_fowner ||
+                       error "nodemap_set_cap +cap_fowner failed"
+       fi
 }
 run_test 51 "FS capabilities ==============="
 
index f93fa62..879f800 100644 (file)
@@ -195,6 +195,9 @@ command_t nodemap_cmdlist[] = {
         .pc_help = "delete a UID or GID mapping from a nodemap\n"
         "usage: nodemap del_idmap --name NAME --idtype {uid|gid|projid}\n"
         "                         --idmap CLIENTID:FSID"},
+       {.pc_name = "set_cap", .pc_func = jt_nodemap_set_cap,
+        .pc_help = "define capabilities for regular users on a nodemap\n"
+        "usage: nodemap set_cap --name NODEMAP_NAME --caps CAPABILITIES --type {mask|set|off}"},
        {.pc_name = "set_fileset", .pc_func = jt_nodemap_set_fileset,
         .pc_help = "set a fileset on a nodemap\n"
         "usage: nodemap set_fileset --name NODEMAP_NAME --fileset FILESET"},
@@ -626,6 +629,9 @@ command_t cmdlist[] = {
        {"nodemap_set_sepol", jt_nodemap_set_sepol, 0,
         "set SELinux policy info on a nodemap\n"
         "usage: nodemap_set_sepol --name NODEMAP_NAME --sepol SEPOL"},
+       {"nodemap_set_cap", jt_nodemap_set_cap, NULL,
+        "defines capabilities for regular users on a nodemap\n"
+        "usage: nodemap_set_cap --name NODEMAP_NAME --caps CAPABILITIES --type {mask|set|off}"},
        {"nodemap_test_nid", jt_nodemap_test_nid, 0,
         "test a nid for nodemap membership\n"
         "usage: nodemap_test_nid --nid NID"},
index e57727c..0f317a3 100644 (file)
@@ -4632,6 +4632,89 @@ set_sepol_usage:
 }
 
 /**
+ * jt_nodemap_set_cap() - Define capabilities for regular users
+ *                       on the specified nodemap
+ * @argc: number of args
+ * @argv: variable string arguments
+ *
+ * --name nodemap name
+ * --caps user capabilities
+ * --type mask or set or off
+ *
+ * Return:
+ * * %0 on success
+ */
+int jt_nodemap_set_cap(int argc, char **argv)
+{
+       char *nodemap_name = NULL;
+       char *param = NULL;
+       char *caps = NULL;
+       char *type = NULL;
+       int c, len, rc = 0;
+
+       struct option long_options[] = {
+          { .val = 'c', .name = "caps",         .has_arg = required_argument },
+          { .val = 'c', .name = "capabilities", .has_arg = required_argument },
+          { .val = 'h', .name = "help",         .has_arg = no_argument },
+          { .val = 'n', .name = "name",         .has_arg = required_argument },
+          { .val = 't', .name = "type",         .has_arg = required_argument },
+          { .name = NULL },
+       };
+
+       while ((c = getopt_long(argc, argv, "c:hn:t:",
+                               long_options, NULL)) != -1) {
+               switch (c) {
+               case 'c':
+                       caps = optarg;
+                       break;
+               case 'n':
+                       nodemap_name = optarg;
+                       break;
+               case 't':
+                       type = optarg;
+                       break;
+               case 'h':
+               default:
+                       return CMD_HELP;
+               }
+       }
+
+       if (!nodemap_name) {
+               fprintf(stderr, "nodemap_set_cap: missing nodemap name\n");
+               return CMD_HELP;
+       }
+       if (!type) {
+               fprintf(stderr, "nodemap_set_cap: missing caps type\n");
+               return CMD_HELP;
+       }
+       if (!caps && strcmp(type, "off") != 0) {
+               fprintf(stderr, "nodemap_set_cap: missing capabilities\n");
+               return CMD_HELP;
+       }
+
+       len = strlen(type) + 2;
+       if (caps)
+               len += strlen(caps);
+       param = malloc(len);
+       if (!param) {
+               fprintf(stderr, "nodemap_set_cap: cannot allocate param\n");
+               return -ENOMEM;
+       }
+       snprintf(param, len, "%s:%s", type, caps);
+       rc = nodemap_cmd(LCFG_NODEMAP_SET_CAPS, false, NULL, 0, argv[0],
+                        nodemap_name, param, NULL);
+       free(param);
+       if (rc != 0) {
+               fprintf(stderr,
+                       "error: %s: cannot set capabilities '%s' on nodemap '%s': %s\n",
+                       jt_cmdname(argv[0]), caps, nodemap_name,
+                       strerror(errno));
+       }
+
+       return rc;
+}
+
+/**
  * modify a nodemap's behavior
  *
  * \param      argc            number of args
@@ -5412,6 +5495,12 @@ int jt_nodemap_set_sepol(int argc, char **argv)
        return -EOPNOTSUPP;
 }
 
+int jt_nodemap_set_cap(int argc, char **argv)
+{
+       fprintf(stderr, "error: %s: invalid ioctl\n", jt_cmdname(argv[0]));
+       return -EOPNOTSUPP;
+}
+
 int jt_nodemap_info(int argc, char **argv)
 {
        fprintf(stderr, "error: %s: invalid ioctl\n",
index 5e7efc5..d114f0b 100644 (file)
@@ -196,6 +196,7 @@ int jt_nodemap_del_idmap(int argc, char **argv);
 int jt_nodemap_test_id(int argc, char **argv);
 int jt_nodemap_set_fileset(int argc, char **argv);
 int jt_nodemap_set_sepol(int argc, char **argv);
+int jt_nodemap_set_cap(int argc, char **argv);
 int jt_nodemap_info(int argc, char **argv);
 int jt_changelog_register(int argc, char **argv);
 int jt_changelog_deregister(int argc, char **argv);
index 1851355..8a1f670 100644 (file)
@@ -2999,6 +2999,19 @@ static void check_nodemap_offset_rec(void)
        CHECK_MEMBER(nodemap_offset_rec, nor_padding2);
 }
 
+static void check_nodemap_capabilities_rec(void)
+{
+       BLANK_LINE();
+       CHECK_STRUCT(nodemap_user_capabilities_rec);
+       CHECK_MEMBER(nodemap_user_capabilities_rec, nucr_caps);
+       CHECK_MEMBER(nodemap_user_capabilities_rec, nucr_type);
+       CHECK_MEMBER(nodemap_user_capabilities_rec, nucr_padding1);
+       CHECK_MEMBER(nodemap_user_capabilities_rec, nucr_padding2);
+       CHECK_MEMBER(nodemap_user_capabilities_rec, nucr_padding3);
+       CHECK_MEMBER(nodemap_user_capabilities_rec, nucr_padding4);
+       CHECK_MEMBER(nodemap_user_capabilities_rec, nucr_padding5);
+}
+
 static void check_nodemap_global_rec(void)
 {
        BLANK_LINE();
@@ -3059,6 +3072,7 @@ static void check_nodemap_key(void)
        CHECK_VALUE(NODEMAP_CLUSTER_REC);
        CHECK_VALUE(NODEMAP_CLUSTER_ROLES);
        CHECK_VALUE(NODEMAP_CLUSTER_OFFSET);
+       CHECK_VALUE(NODEMAP_CLUSTER_CAPS);
 
        CHECK_VALUE_X(NM_TYPE_MASK);
        CHECK_VALUE(NM_TYPE_SHIFT);
@@ -3109,6 +3123,7 @@ static void check_nodemap_key(void)
        CHECK_VALUE_X(NODEMAP_RAISE_PRIV_RO);
        CHECK_VALUE_X(NODEMAP_RAISE_PRIV_RBAC);
        CHECK_VALUE_X(NODEMAP_RAISE_PRIV_FORBID_ENC);
+       CHECK_VALUE_X(NODEMAP_RAISE_PRIV_CAPS);
        CHECK_VALUE_X(NODEMAP_RAISE_PRIV_NONE);
        CHECK_VALUE_X(NODEMAP_RAISE_PRIV_ALL);
 }
@@ -3373,6 +3388,7 @@ check_lustre_cfg(void)
        CHECK_VALUE_X(LCFG_NODEMAP_RBAC);
        CHECK_VALUE_X(LCFG_NODEMAP_DENY_MOUNT);
        CHECK_VALUE_X(LCFG_NODEMAP_RAISE_PRIVS);
+       CHECK_VALUE_X(LCFG_NODEMAP_SET_CAPS);
        printf("#endif /* HAVE_SERVER_SUPPORT */\n");
 #endif /* !HAVE_NATIVE_LINUX_CLIENT */
        CHECK_VALUE(PORTALS_CFG_TYPE);
@@ -3825,6 +3841,7 @@ main(int argc, char **argv)
        check_nodemap_range2_rec();
        check_nodemap_id_rec();
        check_nodemap_offset_rec();
+       check_nodemap_capabilities_rec();
        check_nodemap_global_rec();
        check_nodemap_cluster_roles_rec();
        check_nodemap_fileset_rec();
index bc4a232..6019ecf 100644 (file)
@@ -6482,6 +6482,38 @@ void lustre_assert_wire_constants(void)
        LASSERTF((int)sizeof(((struct nodemap_fileset_rec *)0)->nfr_padding1) == 2, "found %lld\n",
                 (long long)(int)sizeof(((struct nodemap_fileset_rec *)0)->nfr_padding1));
 
+       /* Checks for struct nodemap_user_capabilities_rec */
+       LASSERTF((int)sizeof(struct nodemap_user_capabilities_rec) == 32, "found %lld\n",
+                (long long)(int)sizeof(struct nodemap_user_capabilities_rec));
+       LASSERTF((int)offsetof(struct nodemap_user_capabilities_rec, nucr_caps) == 0, "found %lld\n",
+                (long long)(int)offsetof(struct nodemap_user_capabilities_rec, nucr_caps));
+       LASSERTF((int)sizeof(((struct nodemap_user_capabilities_rec *)0)->nucr_caps) == 8, "found %lld\n",
+                (long long)(int)sizeof(((struct nodemap_user_capabilities_rec *)0)->nucr_caps));
+       LASSERTF((int)offsetof(struct nodemap_user_capabilities_rec, nucr_type) == 8, "found %lld\n",
+                (long long)(int)offsetof(struct nodemap_user_capabilities_rec, nucr_type));
+       LASSERTF((int)sizeof(((struct nodemap_user_capabilities_rec *)0)->nucr_type) == 1, "found %lld\n",
+                (long long)(int)sizeof(((struct nodemap_user_capabilities_rec *)0)->nucr_type));
+       LASSERTF((int)offsetof(struct nodemap_user_capabilities_rec, nucr_padding1) == 9, "found %lld\n",
+                (long long)(int)offsetof(struct nodemap_user_capabilities_rec, nucr_padding1));
+       LASSERTF((int)sizeof(((struct nodemap_user_capabilities_rec *)0)->nucr_padding1) == 1, "found %lld\n",
+                (long long)(int)sizeof(((struct nodemap_user_capabilities_rec *)0)->nucr_padding1));
+       LASSERTF((int)offsetof(struct nodemap_user_capabilities_rec, nucr_padding2) == 10, "found %lld\n",
+                (long long)(int)offsetof(struct nodemap_user_capabilities_rec, nucr_padding2));
+       LASSERTF((int)sizeof(((struct nodemap_user_capabilities_rec *)0)->nucr_padding2) == 2, "found %lld\n",
+                (long long)(int)sizeof(((struct nodemap_user_capabilities_rec *)0)->nucr_padding2));
+       LASSERTF((int)offsetof(struct nodemap_user_capabilities_rec, nucr_padding3) == 12, "found %lld\n",
+                (long long)(int)offsetof(struct nodemap_user_capabilities_rec, nucr_padding3));
+       LASSERTF((int)sizeof(((struct nodemap_user_capabilities_rec *)0)->nucr_padding3) == 4, "found %lld\n",
+                (long long)(int)sizeof(((struct nodemap_user_capabilities_rec *)0)->nucr_padding3));
+       LASSERTF((int)offsetof(struct nodemap_user_capabilities_rec, nucr_padding4) == 16, "found %lld\n",
+                (long long)(int)offsetof(struct nodemap_user_capabilities_rec, nucr_padding4));
+       LASSERTF((int)sizeof(((struct nodemap_user_capabilities_rec *)0)->nucr_padding4) == 8, "found %lld\n",
+                (long long)(int)sizeof(((struct nodemap_user_capabilities_rec *)0)->nucr_padding4));
+       LASSERTF((int)offsetof(struct nodemap_user_capabilities_rec, nucr_padding5) == 24, "found %lld\n",
+                (long long)(int)offsetof(struct nodemap_user_capabilities_rec, nucr_padding5));
+       LASSERTF((int)sizeof(((struct nodemap_user_capabilities_rec *)0)->nucr_padding5) == 8, "found %lld\n",
+                (long long)(int)sizeof(((struct nodemap_user_capabilities_rec *)0)->nucr_padding5));
+
        /* Checks for union nodemap_rec */
        LASSERTF((int)sizeof(union nodemap_rec) == 32, "found %lld\n",
                 (long long)(int)sizeof(union nodemap_rec));
@@ -6529,6 +6561,8 @@ void lustre_assert_wire_constants(void)
                 (long long)NODEMAP_CLUSTER_ROLES);
        LASSERTF(NODEMAP_CLUSTER_OFFSET == 2, "found %lld\n",
                 (long long)NODEMAP_CLUSTER_OFFSET);
+       LASSERTF(NODEMAP_CLUSTER_CAPS == 3, "found %lld\n",
+                (long long)NODEMAP_CLUSTER_CAPS);
        LASSERTF(NM_TYPE_MASK == 0x0fffffffUL, "found 0x%.8xUL\n",
                (unsigned)NM_TYPE_MASK);
        LASSERTF(NM_TYPE_SHIFT == 28, "found %lld\n",
@@ -6615,7 +6649,9 @@ void lustre_assert_wire_constants(void)
                 (unsigned)NODEMAP_RAISE_PRIV_RBAC);
        LASSERTF(NODEMAP_RAISE_PRIV_FORBID_ENC == 0x00000040UL, "found 0x%.8xUL\n",
                 (unsigned)NODEMAP_RAISE_PRIV_FORBID_ENC);
-       LASSERTF(NODEMAP_RAISE_PRIV_NONE == 0xffffff80UL, "found 0x%.8xUL\n",
+       LASSERTF(NODEMAP_RAISE_PRIV_CAPS == 0x00000080UL, "found 0x%.8xUL\n",
+                (unsigned)NODEMAP_RAISE_PRIV_CAPS);
+       LASSERTF(NODEMAP_RAISE_PRIV_NONE == 0xffffff00UL, "found 0x%.8xUL\n",
                 (unsigned)NODEMAP_RAISE_PRIV_NONE);
        LASSERTF(NODEMAP_RAISE_PRIV_ALL == 0xffffffffUL, "found 0x%.8xUL\n",
                 (unsigned)NODEMAP_RAISE_PRIV_ALL);
@@ -7195,6 +7231,8 @@ void lustre_assert_wire_constants(void)
                (unsigned int)LCFG_NODEMAP_DENY_MOUNT);
        LASSERTF(LCFG_NODEMAP_RAISE_PRIVS == 0x000ce061UL, "found 0x%.8xUL\n",
                 (unsigned)LCFG_NODEMAP_RAISE_PRIVS);
+       LASSERTF(LCFG_NODEMAP_SET_CAPS == 0x00ce063UL, "found 0x%.8xUL\n",
+                (unsigned)LCFG_NODEMAP_SET_CAPS);
 #endif /* HAVE_SERVER_SUPPORT */
        LASSERTF(PORTALS_CFG_TYPE == 1, "found %lld\n",
                 (long long)PORTALS_CFG_TYPE);