zfs_fuid.c revision a078ff4a0f321365c3ca4cd812df95c377f50916
/*
* CDDL HEADER START
*
* The contents of this file are subject to the terms of the
* Common Development and Distribution License (the "License").
* You may not use this file except in compliance with the License.
*
* You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
* See the License for the specific language governing permissions
* and limitations under the License.
*
* When distributing Covered Code, include this CDDL HEADER in each
* file and include the License file at usr/src/OPENSOLARIS.LICENSE.
* If applicable, add the following below this CDDL HEADER, with the
* fields enclosed by brackets "[]" replaced with your own identifying
* information: Portions Copyright [yyyy] [name of copyright owner]
*
* CDDL HEADER END
*/
/*
* Copyright 2008 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
*/
#include <sys/zfs_context.h>
#include <sys/refcount.h>
#ifdef _KERNEL
#include <sys/zfs_vfsops.h>
#include <sys/zfs_znode.h>
#endif
#include <sys/zfs_fuid.h>
/*
* FUID Domain table(s).
*
* The FUID table is stored as a packed nvlist of an array
* of nvlists which contain an index, domain string and offset
*
* During file system initialization the nvlist(s) are read and
* two AVL trees are created. One tree is keyed by the index number
* and the other by the domain string. Nodes are never removed from
* trees, but new entries may be added. If a new entry is added then the
* on-disk packed nvlist will also be updated.
*/
#define FUID_IDX "fuid_idx"
#define FUID_DOMAIN "fuid_domain"
#define FUID_OFFSET "fuid_offset"
#define FUID_NVP_ARRAY "fuid_nvlist"
typedef struct fuid_domain {
/*
* Compare two indexes.
*/
static int
{
return (-1);
return (1);
return (0);
}
/*
* Compare two domain strings.
*/
static int
{
int val;
if (val == 0)
return (0);
}
/*
* load initial fuid domain and idx trees. This function is used by
* both the kernel and zdb.
*/
{
if (fuid_size) {
char *packed;
int i;
&nvp, 0) == 0);
for (i = 0; i != count; i++) {
char *domain;
&domain) == 0);
&idx) == 0);
}
}
return (fuid_size);
}
void
{
void *cookie;
}
char *
{
}
#ifdef _KERNEL
/*
* Load the fuid table(s) into memory.
*/
static void
{
int error = 0;
if (zfsvfs->z_fuid_loaded) {
return;
}
if (zfsvfs->z_fuid_obj == 0) {
/* first make sure we need to allocate object */
}
}
}
/*
* Query domain table for a given domain.
*
* If domain isn't found it is added to AVL trees and
* the results are pushed out to disk.
*/
int
{
/*
* If the dummy "nobody" domain then return an index of 0
* to cause the created FUID to be a standard POSIX id
* for the user nobody.
*/
if (domain[0] == '\0') {
*retdomain = "";
return (0);
}
if (retdomain) {
}
if (!zfsvfs->z_fuid_loaded)
if (findnode) {
} else {
char *packed;
int i = 0;
goto retry;
}
/*
* Now resync the on-disk nvlist.
*/
while (domnode) {
NV_UNIQUE_NAME, KM_SLEEP) == 0);
FUID_OFFSET, 0) == 0);
}
for (i = 0; i != retidx; i++)
nvlist_free(fuids[i]);
NV_ENCODE_XDR, KM_SLEEP) == 0);
return (retidx);
}
}
/*
* Query domain table by index, returning domain string
*
* Returns a pointer from an avl node of the domain string.
*
*/
static char *
{
char *domain;
return (NULL);
if (!zfsvfs->z_fuid_loaded)
return (domain);
}
void
{
}
{
char *domain;
if (index == 0)
return (fuid);
} else {
}
return (id);
}
/*
* Add a FUID node to the list of fuid's being created for this
* ACL
*
* If ACL has multiple domains, then keep only one copy of each unique
* domain.
*/
static void
{
*fuidpp = zfs_fuid_info_alloc();
/*
* First find fuid domain index in linked list
*
* If one isn't found then create an entry.
*/
fuid_domain), fuididx++) {
break;
}
}
if (!found) {
fuidp->z_domain_cnt++;
}
/*
* Now allocate fuid entry and add it on the end of the list
*/
fuidp->z_fuid_cnt++;
} else {
else
}
}
/*
* Create a file system FUID, based on information in the users cred
*/
{
char *kdomain;
const char *domain;
else
}
/*
* Create a file system FUID for an ACL ace
* This is similar to zfs_fuid_create_cred, except that
* we can't find the domain + rid information in the
* cred. Instead we have to query Winchester for the
* domain and rid.
*
* During replay operations the domain+rid information is
* found in the zfs_fuid_info_t that the replay code has
* attached to the zfsvfs of the file system.
*/
{
const char *domain;
char *kdomain;
/*
* If POSIX ID, or entry is already a FUID then
* just return the id
*
* We may also be handed an already FUID'ized id via
* chmod.
*/
return (id);
if (is_replay) {
/*
* If we are passed an ephemeral id, but no
* fuid_info was logged then return NOBODY.
* This is most likely a result of idmap service
* not being available.
*/
return (UID_NOBODY);
switch (type) {
case ZFS_ACE_USER:
case ZFS_ACE_GROUP:
break;
case ZFS_OWNER:
break;
case ZFS_GROUP:
break;
};
} else {
else
if (status != 0) {
/*
* When returning nobody we will need to
* make a dummy fuid table entry for logging
* purposes.
*/
rid = UID_NOBODY;
domain = "";
}
}
if (!is_replay)
}
}
void
{
if (!zfsvfs->z_fuid_loaded) {
return;
}
}
/*
* Allocate zfs_fuid_info for tracking FUIDs created during
* zfs_mknode, VOP_SETATTR() or VOP_SETSECATTR()
*/
zfs_fuid_info_alloc(void)
{
return (fuidp);
}
/*
* Release all memory associated with zfs_fuid_info_t
*/
void
{
}
(sizeof (char **)) * fuidp->z_domain_cnt);
}
}
/*
* Check to see if id is a groupmember. If cred
* has ksid info then sidlist is checked first
* and if still not found then POSIX groups are checked
*
* Will use a straight FUID compare when possible.
*/
{
if (ksid) {
int i;
if (idx == 0) {
if (id != IDMAP_WK_CREATOR_GROUP_GID &&
return (B_TRUE);
}
} else {
char *domain;
return (B_FALSE);
return (B_TRUE);
}
}
}
/*
* Not found in ksidlist, check posix groups
*/
}
#endif