libcfs.h \
libcfs_debug.h \
libcfs_fail.h \
- libcfs_private.h
+ libcfs_private.h \
+ libcfs_caps.h
--- /dev/null
+/* 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
str[len++] = '\n';
if (len < size)
str[len] = '\0';
- else
+ else if (size)
str[size - 1] = '\0';
return len;
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 \
.br
- child_raise_privs
.br
+- caps
+.br
It is also possible to specify any roles accepted by the
.B rbac
property (see below).
--- /dev/null
+.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)
--- /dev/null
+.so man8/lctl-nodemap-set-cap.8
-.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
.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
.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),
{ 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;
{ 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
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 */
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
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);
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 {
__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;
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 */
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
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
*/
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.
*/
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
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,
&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
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,
#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
}
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,
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)
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;
}
#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"
* - 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:
* - 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
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;
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;
}
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;
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:
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
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;
}
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);
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]);
#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);
}
/**
+ * 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
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);
.fops = &nodemap_deny_unknown_fops,
},
{
+ .name = "enable_cap_mask",
+ .fops = &nodemap_capabilities_fops,
+ },
+ {
.name = "exports",
.fops = &nodemap_exports_fops,
},
.fops = &nodemap_deny_unknown_fops,
},
{
+ .name = "enable_cap_mask",
+ .fops = &nodemap_capabilities_fops,
+ },
+ {
.name = "exports",
.fops = &nodemap_exports_fops,
},
#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 */
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)
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);
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) {
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)
{
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.
*
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 +
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) {
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));
(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",
(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);
(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);
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
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 &&
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 ==============="
.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"},
{"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"},
}
/**
+ * 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
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",
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);
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();
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);
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);
}
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);
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();
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));
(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",
(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);
(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);