+ /* we allow sepol = "" which means clear SELinux policy info */
+ if (sepol[0] == '\0')
+ return 0;
+
+ /* make a copy of sepol, by replacing ':' with space
+ * so that we can use sscanf over the string
+ */
+ while (p-sepol < sizeof(buf)) {
+ if (*p == ':')
+ *q = ' ';
+ else
+ *q = *p;
+ if (*p == '\0')
+ break;
+ p++;
+ q++;
+ }
+ if (p-sepol == sizeof(buf))
+ return -ENAMETOOLONG;
+
+ if (sscanf(buf, "%1hhu %s %hu %s", &mode, polname, &ver, hash) != 4)
+ return -EINVAL;
+
+ if (mode != 0 && mode != 1)
+ return -EINVAL;
+
+ return 0;
+}
+
+/**
+ * set SELinux policy on nodemap
+ * \param name nodemap to set SELinux policy info on
+ * \param sepol string containing SELinux policy info
+ * \retval 0 on success
+ *
+ * set SELinux policy info on the named nodemap
+ */
+int nodemap_set_sepol(const char *name, const char *sepol)
+{
+ struct lu_nodemap *nodemap = NULL;
+ int rc;
+
+ rc = nodemap_validate_sepol(sepol);
+ if (rc < 0)
+ GOTO(out, rc);
+
+ mutex_lock(&active_config_lock);
+ nodemap = nodemap_lookup(name);
+ if (IS_ERR(nodemap)) {
+ mutex_unlock(&active_config_lock);
+ GOTO(out, rc = PTR_ERR(nodemap));
+ }
+
+ if (is_default_nodemap(nodemap)) {
+ /* We do not want nodes in the default nodemap to have
+ * SELinux restrictions. Sec admin should create dedicated
+ * nodemap entries for this.
+ */
+ GOTO(out_putref, rc = -EINVAL);
+ }
+
+ /* truncation cannot happen, as string length was checked in
+ * nodemap_validate_sepol()
+ */
+ strlcpy(nodemap->nm_sepol, sepol, sizeof(nodemap->nm_sepol));
+
+out_putref:
+ mutex_unlock(&active_config_lock);
+ nodemap_putref(nodemap);
+out:
+ return rc;
+}
+EXPORT_SYMBOL(nodemap_set_sepol);
+
+/**
+ * get SELinux policy info defined on nodemap
+ * \param nodemap nodemap to get SELinux policy info from
+ * \retval SELinux policy info, or NULL if not defined or not activated
+ *
+ * get the SELinux policy info defined on the nodemap
+ */
+const char *nodemap_get_sepol(const struct lu_nodemap *nodemap)
+{
+ if (is_default_nodemap(nodemap))
+ return NULL;
+ else
+ return (char *)nodemap->nm_sepol;
+}
+EXPORT_SYMBOL(nodemap_get_sepol);
+
+/**
+ * Nodemap constructor
+ *
+ * Creates an lu_nodemap structure and assigns sane default
+ * member values. If this is the default nodemap, the defaults
+ * are the most restrictive in terms of mapping behavior. Otherwise
+ * the default flags should be inherited from the default nodemap.
+ * The adds nodemap to nodemap_hash.
+ *
+ * Requires that the caller take the active_config_lock
+ *
+ * \param name name of nodemap
+ * \param is_default true if default nodemap
+ * \retval nodemap success
+ * \retval -EINVAL invalid nodemap name
+ * \retval -EEXIST nodemap already exists
+ * \retval -ENOMEM cannot allocate memory for nodemap
+ */
+struct lu_nodemap *nodemap_create(const char *name,
+ struct nodemap_config *config,
+ bool is_default)
+{
+ struct lu_nodemap *nodemap = NULL;
+ struct lu_nodemap *default_nodemap;
+ struct cfs_hash *hash = config->nmc_nodemap_hash;
+ int rc = 0;
+ ENTRY;
+
+ default_nodemap = config->nmc_default_nodemap;
+
+ if (!nodemap_name_is_valid(name))
+ GOTO(out, rc = -EINVAL);
+
+ if (hash == NULL) {
+ CERROR("Config nodemap hash is NULL, unable to add %s\n", name);
+ GOTO(out, rc = -EINVAL);
+ }
+
+ OBD_ALLOC_PTR(nodemap);
+ if (nodemap == NULL) {
+ CERROR("cannot allocate memory (%zu bytes) for nodemap '%s'\n",
+ sizeof(*nodemap), name);
+ GOTO(out, rc = -ENOMEM);
+ }
+
+ /*
+ * take an extra reference to prevent nodemap from being destroyed
+ * while it's being created.
+ */
+ atomic_set(&nodemap->nm_refcount, 2);
+ snprintf(nodemap->nm_name, sizeof(nodemap->nm_name), "%s", name);
+ rc = cfs_hash_add_unique(hash, name, &nodemap->nm_hash);
+ if (rc != 0) {
+ OBD_FREE_PTR(nodemap);
+ GOTO(out, rc = -EEXIST);
+ }
+
+ INIT_LIST_HEAD(&nodemap->nm_ranges);
+ INIT_LIST_HEAD(&nodemap->nm_list);
+ INIT_LIST_HEAD(&nodemap->nm_member_list);
+
+ mutex_init(&nodemap->nm_member_list_lock);
+ init_rwsem(&nodemap->nm_idmap_lock);
+ nodemap->nm_fs_to_client_uidmap = RB_ROOT;
+ nodemap->nm_client_to_fs_uidmap = RB_ROOT;
+ nodemap->nm_fs_to_client_gidmap = RB_ROOT;
+ nodemap->nm_client_to_fs_gidmap = RB_ROOT;
+ nodemap->nm_fs_to_client_projidmap = RB_ROOT;
+ nodemap->nm_client_to_fs_projidmap = RB_ROOT;
+
+ if (is_default) {
+ nodemap->nm_id = LUSTRE_NODEMAP_DEFAULT_ID;
+ config->nmc_default_nodemap = nodemap;
+ } else {
+ config->nmc_nodemap_highest_id++;
+ nodemap->nm_id = config->nmc_nodemap_highest_id;
+ }
+
+ if (is_default || default_nodemap == NULL) {
+ nodemap->nmf_trust_client_ids = 0;
+ nodemap->nmf_allow_root_access = 0;
+ nodemap->nmf_deny_unknown = 0;
+ nodemap->nmf_map_mode = NODEMAP_MAP_ALL;
+ nodemap->nmf_enable_audit = 1;
+ nodemap->nmf_forbid_encryption = 0;
+ nodemap->nmf_readonly_mount = 0;
+
+ nodemap->nm_squash_uid = NODEMAP_NOBODY_UID;
+ nodemap->nm_squash_gid = NODEMAP_NOBODY_GID;
+ nodemap->nm_squash_projid = NODEMAP_NOBODY_PROJID;
+ nodemap->nm_fileset[0] = '\0';
+ nodemap->nm_sepol[0] = '\0';
+ if (!is_default)
+ CWARN("adding nodemap '%s' to config without"
+ " default nodemap\n", nodemap->nm_name);