Files
mars-nwe/src/nwnss/comn/authsys/zasAuthModel.c
2026-06-16 20:21:02 +02:00

5793 lines
164 KiB
C

/****************************************************************************
|
| (C) Copyright 1996 - 2005 Novell, Inc.
| All Rights Reserved.
|
| This program is free software; you can redistribute it and/or
| modify it under the terms of version 2 of the GNU General Public
| License as published by the Free Software Foundation.
|
| This program is distributed in the hope that it will be useful,
| but WITHOUT ANY WARRANTY; without even the implied warranty of
| MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
| GNU General Public License for more details.
|
| You should have received a copy of the GNU General Public License
| along with this program; if not, contact Novell, Inc.
|
| To contact Novell about this file by physical or electronic mail,
| you may find current contact information at www.novell.com
|
|***************************************************************************
|
| Novell Storage Services (NSS) module
|
|---------------------------------------------------------------------------
|
| $Author: gpachner $
| $Date: 2008-04-11 02:30:25 +0530 (Fri, 11 Apr 2008) $
|
| $RCSfile$
| $Revision: 2315 $
|
|---------------------------------------------------------------------------
| This module is used to:
| These are the authorization routines that are model specific.
+-------------------------------------------------------------------------*/
#include <procdefs.h>
#include <version.h>
#include <portable.h>
#include <connect.h>
#include <connexp.h> /* NetWare Source*/
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <xError.h>
#include <omni.h> /* NSS Library*/
#include "zParams.h"
#include "zasAuthModel.h"
#include "zasAuthSpace.h"
#include "unixAuthSpace.h"
#include "msgGen.h"
#include "zasAuthCache.h"
#include "pssConnection.h"
#include "comnPublics.h"
#include "comnBeasts.h"
//#include "sanwErr.h"
#include "volume.h"
#include "pssStartup.h"
#include "msgName.h"
#include "nameSpace.h"
#include "comnZAS.h"
#include "guid.h"
#include "adminVolume.h"
#include "comnLock.h"
#include "objectIDStore.h"
#include "xAdminVolume.h"
#include "checker.h"
#include "nssPubs.h"
#include "hardLinkBeast.h"
/*-------------------------------------------------------------------------
* Global variables
*-------------------------------------------------------------------------*/
NINT ZASindex; /* the index assigned to the Z authorization space */
BOOL AuthorizeStarted = FALSE;
STATUS ZAS_RemoveLatchedACLEntry(
GeneralMsg_s *genMsg,
AuthBeast_s *authBeast,
UserID_t *trusteeID,
NINT purgedFileFlag,
Xaction_s *xaction);
STATUS ZAS_CountVis(
GeneralMsg_s *genMsg,
AuthBeast_s *authBeast,
NINT *entryCount);
STATUS ZAS_GetAllVis(
GeneralMsg_s *genMsg,
AuthBeast_s *authBeast,
VisEntry_s *vis,
NINT count);
/* Visibility rebuild stats */
typedef struct VisRebuildStats_s
{
QUAD VisNumBeasts;
QUAD VisNumOverflowRemoved;
QUAD VisNumFilesCleaned;
QUAD VisNumTrusteesProcessed;
} VisRebuildStats_s;
typedef struct VisRebParms_s
{
Volume_s *vol;
unicode_t name[zMAX_COMPONENT_NAME];
} VisRebParms_s;
/****************************************************************************
*
****************************************************************************/
void *ZAS_LookupOverflowBeast (
GeneralMsg_s *genMsg,
void *voidVol,
Zid_t zid,
NINT latchType,
NINT classID)
{
RootBeast_s *beast;
beast = BEASTHASH_LookupByZid(genMsg, voidVol, zid, latchType);
if (beast == NULL)
{
return NULL;
}
if (!(COMN_IsDerivedFrom(beast, classID)))
{
zASSERT("Overflow beast is not the correct type" == NULL);
COMN_UnlatchAndRelease(&beast, latchType);
return NULL;
}
return beast;
}
/****************************************************************************
*
****************************************************************************/
#if NSS_DEBUG IS_ENABLED
/* Authorization useage information */
NINT AuthResets = 0;
NINT AuthPartialResets = 0;
NINT AuthERRequests = 0;
NINT AuthERHits = 0;
NINT AuthERImmediateHits = 0;
/****************************************************************************
*
****************************************************************************/
void DEBUG_Display_Visibility(
AuthBeast_s *authBeast)
{
NINT entry;
ZASAuthorizeInfo_s *authInfo;
ZasVisOverflowBeast_s *overflowBeast;
Zid_t overflowZid;
GeneralMsg_s genMsg;
ASSERT_MPKNSS_LOCK();
COMN_SETUP_GENERAL_MSG_NO_CONNECTION_RESOLVE(&genMsg);
DBG_DebugPrintf(GREEN, MSGNot("\nVisiblibilty entries for ZID 0x%Lx\n"), authBeast->AUTHzid);
authInfo = authBeast->AUTHauthInfo.zas;
/* display the entries in the main beast */
for (entry=0; entry < authInfo->p.numVisibilityTrusteesAssigned; entry++)
{
DBG_DebugPrintf(CYAN, MSGNot(" (%d) Trustee: %08x-%04x-%04x-%02x%02x-%02x%02x%02x%02x%02x%02x Count: %d\n"),
entry,
authInfo->p.visibilityList[entry].trusteeID.timeLow,
authInfo->p.visibilityList[entry].trusteeID.timeMid,
authInfo->p.visibilityList[entry].trusteeID.timeHighAndVersion,
authInfo->p.visibilityList[entry].trusteeID.clockSeqHighAndReserved,
authInfo->p.visibilityList[entry].trusteeID.clockSeqLow,
authInfo->p.visibilityList[entry].trusteeID.node[0],
authInfo->p.visibilityList[entry].trusteeID.node[1],
authInfo->p.visibilityList[entry].trusteeID.node[2],
authInfo->p.visibilityList[entry].trusteeID.node[3],
authInfo->p.visibilityList[entry].trusteeID.node[4],
authInfo->p.visibilityList[entry].trusteeID.node[5],
authInfo->p.visibilityList[entry].count);
}
/* display the entries in the overflow beasts */
overflowZid = authInfo->p.visibilityOverflow;
while (overflowZid != zINVALID_ZID)
{
/* get the next overflow beast */
overflowBeast = ZAS_LookupOverflowBeast(&genMsg, authBeast->AUTHvolume,
overflowZid, SLATCHED, zFTYPE_ZAS_VIS_OVERFLOW);
if (overflowBeast == NULL)
{ /* error */
DBG_DebugPrintf(RED, MSGNot("Error opening an overflow beast: %d\n"), GetErrno(&genMsg));
return;
}
for (entry=0; entry < overflowBeast->p.numEntries; entry++)
{
DBG_DebugPrintf(LBLUE, MSGNot(" (%d) Trustee: %08x-%04x-%04x-%02x%02x-%02x%02x%02x%02x%02x%02x Count: %d\n"),
entry,
overflowBeast->vis[entry].trusteeID.timeLow,
overflowBeast->vis[entry].trusteeID.timeMid,
overflowBeast->vis[entry].trusteeID.timeHighAndVersion,
overflowBeast->vis[entry].trusteeID.clockSeqHighAndReserved,
overflowBeast->vis[entry].trusteeID.clockSeqLow,
overflowBeast->vis[entry].trusteeID.node[0],
overflowBeast->vis[entry].trusteeID.node[1],
overflowBeast->vis[entry].trusteeID.node[2],
overflowBeast->vis[entry].trusteeID.node[3],
overflowBeast->vis[entry].trusteeID.node[4],
overflowBeast->vis[entry].trusteeID.node[5],
overflowBeast->vis[entry].count);
}
overflowZid = overflowBeast->p.nextOverflowZid;
zASSERT((overflowZid == zINVALID_ZID) ||
(overflowBeast->p.numEntries == MAX_VIS_OVERFLOW_ENTRIES));
COMN_UnlatchAndRelease(&overflowBeast, SLATCHED);
}
}
#endif
/***************************************************************************
* The authorization operations for the system
* (FixFixFix6 -- these should be loaded)
***************************************************************************/
struct AuthModelOps_s ZASAuthorizeModelOps =
{
VAUTH_ConstructAuthBeast,
VAUTH_DestructAuthBeast,
VAUTH_PackedSize,
VAUTH_PackAuthBeast,
VAUTH_NoPackAuthBeastCleanup,
VAUTH_UnpackAuthBeast,
VAUTH_AddAuthInfo,
VAUTH_RemoveAuthInfo,
VAUTH_DeleteAuthInfo,
VAUTH_IsAuthInfo,
VAUTH_MayIDoThis,
VAUTH_InitVolumeAuthInfo,
VAUTH_RemoveIDsFromAVolume,
VAUTH_AddObjectNames,
VAUTH_CheckUserIDs,
VAUTH_InvalidateAuthInfo,
};
/***************************************************************************
* This will be called at Authorization model init time
***************************************************************************/
STATUS ZAS_Startup(void)
{
GeneralMsg_s genMsg;
AuthModelBeast_s *authModel;
AuthSpaceBeast_s *authSpace;
ASSERT_MPKNSS_LOCK();
ENTER(TAUTH, ZAS_Startup);
COMN_STRUCT_INIT(genMsg);
COMN_SETUP_GENERAL_MSG_NOSA(&genMsg);
if ((authModel = COMN_RegisterAuthorizeModel(&genMsg, AUTH_MODEL_VERSION,
zFTYPE_ZAS_AUTH_MODEL, MSGNot("NetWare"),
&ZASAuthorizeModelOps)) == NULL)
{
RTN_STATUS(zFAILURE);
}
if ((authSpace = COMN_RegisterAuthorizeSpace(&genMsg, authModel,
zFTYPE_ZAS_AUTH_SPACE, MSGNot("NetWareToNetWare"),
(AuthSpaceOps_s *)&ZASAuthorizeSpaceOps)) == NULL)
{
RTN_STATUS(zFAILURE);
}
ZASindex = authSpace->spaceIndex;
if (ZAS_CacheInit(&genMsg) != zOK)
{
RTN_STATUS(zFAILURE);
}
if ((authSpace = COMN_RegisterAuthorizeSpace(&genMsg, authModel,
zFTYPE_UNIX_AUTH_SPACE, MSGNot("UnixToNetWare"),
(AuthSpaceOps_s *)&UnixToNetWareAuthorizeSpaceOps)) == NULL)
{
RTN_STATUS(zFAILURE);
}
UXASindex = authSpace->spaceIndex;
AuthorizeStarted = TRUE;
RTN_STATUS(zOK);
}
/***************************************************************************
* This will be called at Authorization shutdown time
***************************************************************************/
void ZAS_Shutdown(void)
{
ENTER(TAUTH, ZAS_Shutdown);
ASSERT_MPKNSS_LOCK();
ZAS_CacheUninit();
AuthorizeStarted = FALSE;
RTN_VOID();
}
/***************************************************************************
* This routine is called when an auth beast is allocated in memory
* (it may still be on disk)
***************************************************************************/
STATUS VAUTH_ConstructAuthBeast(
GeneralMsg_s *genMsg,
AuthBeast_s *authBeast)
{
ZASAuthorizeInfo_s *authInfo;
ASSERT_MPKNSS_LOCK();
ENTER(TAUTH, VAUTH_ConstructAuthBeast);
authInfo = (ZASAuthorizeInfo_s *)zalloc(sizeof(ZASAuthorizeInfo_s));
if (authInfo == NULL)
{
SetErrno(genMsg,zERR_NO_MEMORY);
RTN_STATUS(zFAILURE);
}
authBeast->AUTHauthInfo.zas = authInfo;
/* authInfo->p.inheritedRightsMask = zAUTHORIZE_SUPERVISOR; *//* always allow superviser to inherit */
authInfo->p.inheritedRightsMask = -1; /* allow all rights */
authInfo->p.cacheIndex = INVALID_EACL_CACHE_INDEX;
authInfo->p.version = CURRENT_AUTH_VERSION;
authInfo->flags = 0;
RTN_STATUS(zOK);
}
/***************************************************************************
* This routine is called when an auth beast is freed from memory
* (it may still be on disk)
***************************************************************************/
void VAUTH_DestructAuthBeast(
AuthBeast_s *authBeast)
{
ASSERT_MPKNSS_LOCK();
ENTER(TAUTH, VAUTH_DestructAuthBeast);
free(authBeast->AUTHauthInfo.zas);
RTN_VOID();
}
/***************************************************************************
* This routine is called when an auth beast is written to storage
***************************************************************************/
NINT VAUTH_PackedSize(
AuthBeast_s *authBeast)
{
ZASAuthorizeInfo_s *authInfo;
ASSERT_MPKNSS_LOCK();
ENTER(TAUTH, VAUTH_PackedSize);
authInfo = authBeast->AUTHauthInfo.zas;
if (!(authInfo->flags & ZAS_ALLOW_FORCED_WRITE))
S_LATCH(&authInfo->authLatch);
RTN_NINT(sizeof(ZASPersistentAuthInfo_s) -
(sizeof(authInfo->p.ACL) + sizeof(authInfo->p.visibilityList)) +
sizeof(ACLEntry_s) * authInfo->p.numTrusteesAssigned +
sizeof(VisEntry_s) * authInfo->p.numVisibilityTrusteesAssigned);
}
/***************************************************************************
* This routine is called when an auth beast is written to storage
***************************************************************************/
BYTE *VAUTH_PackAuthBeast(
AuthBeast_s *authBeast,
BYTE *storeBuffer)
{
ZASAuthorizeInfo_s *authInfo;
NINT len;
ASSERT_MPKNSS_LOCK();
ENTER(TAUTH, VAUTH_PackAuthBeast);
authInfo = authBeast->AUTHauthInfo.zas;
zASSERT((authInfo->flags & ZAS_ALLOW_FORCED_WRITE) ||
(authBeast->AUTHauthInfo.zas->authLatch.count != 0));
// now being latched in VAUTH_PackedSize
// if (!(authInfo->flags & ZAS_ALLOW_FORCED_WRITE))
// S_LATCH(&authInfo->authLatch);
len = sizeof(ZASPersistentAuthInfo_s) -
(sizeof(authInfo->p.ACL) + sizeof(authInfo->p.visibilityList));
memcpy(storeBuffer, &authInfo->p, len);
storeBuffer += len;
len = sizeof(ACLEntry_s) * authInfo->p.numTrusteesAssigned;
memcpy(storeBuffer, &authInfo->p.ACL, len);
storeBuffer += len;
len = sizeof(VisEntry_s) * authInfo->p.numVisibilityTrusteesAssigned;
memcpy(storeBuffer, &authInfo->p.visibilityList, len);
if (!(authInfo->flags & ZAS_ALLOW_FORCED_WRITE))
UNS_LATCH(&authInfo->authLatch);
RTN_PTR(storeBuffer + len);
}
/**************************************************************************
* This routine is called when we have done a "getPackedSize" but we can't
* do the pack do to an error. This will cleanup the latch that we
* aquired at "getPackedSize" time.
***************************************************************************/
void VAUTH_NoPackAuthBeastCleanup(
AuthBeast_s *authBeast)
{
ZASAuthorizeInfo_s *authInfo;
ASSERT_MPKNSS_LOCK();
ENTER(TAUTH, VAUTH_NoPackAuthBeastCleanup);
authInfo = authBeast->AUTHauthInfo.zas;
if (!(authInfo->flags & ZAS_ALLOW_FORCED_WRITE))
UNS_LATCH(&authInfo->authLatch);
RTN_VOID();
}
/***************************************************************************
* This routine is called when an auth beast is read from storage
***************************************************************************/
BYTE *VAUTH_UnpackAuthBeast(
GeneralMsg_s *genMsg,
AuthBeast_s *authBeast,
BYTE *storeBuffer)
{
ZASAuthorizeInfo_s *authInfo;
V1_ZASPersistentAuthInfo_s *oldInfo;
V1_ACLEntry_s *oldACLEntry;
V1_VisEntry_s *oldVisEntry;
NINT len;
NINT count;
STATUS status;
NINT inner;
VisEntry_s temp;
NINT convertCount;
ASSERT_MPKNSS_LOCK();
ENTER(TAUTH, VAUTH_UnpackAuthBeast);
authInfo = authBeast->AUTHauthInfo.zas;
X_LATCH(&authInfo->authLatch);
/*
* Perform an on-the-fly upgrade upgrade of the auth beast. In the
* future we will check the version number in the persistent auth
* info. Since we are adding it in version two we cannot check it
* this time.
*/
#if (CURRENT_BEAST_VERSION != BEAST_VERSION_3)
#error "Check code here to ensure the new version is handled correctly."
#endif
if (authBeast->AUTHbeastVersion == BEAST_VERSION_1)
{
#if NSS_DEBUG IS_ENABLED
DBG_DebugPrintf(LMAGENTA,"On-the-fly: authorization\n");
#endif
#if (CURRENT_BEAST_VERSION != BEAST_VERSION_3)
#error "Check to see if the beastVersion code below is still correct."
#endif
oldInfo = (V1_ZASPersistentAuthInfo_s *)storeBuffer;
authInfo->p.version = CURRENT_AUTH_VERSION;
authInfo->p.extra1 = 0;
authInfo->p.extra2 = 0;
authInfo->p.cacheIndex = oldInfo->cacheIndex;
authInfo->p.restartCount = oldInfo->restartCount;
authInfo->p.signature = oldInfo->signature;
authInfo->p.inheritedRightsMask = oldInfo->inheritedRightsMask;
authInfo->p.trusteeOverflow = oldInfo->trusteeOverflow;
authInfo->p.visibilityOverflow = oldInfo->visibilityOverflow;
authInfo->p.numTrusteesAssigned = oldInfo->numTrusteesAssigned;
authInfo->p.numVisibilityTrusteesAssigned =
oldInfo->numVisibilityTrusteesAssigned;
storeBuffer += sizeof(V1_ZASPersistentAuthInfo_s);
if( (authInfo->p.numTrusteesAssigned > MAX_TRUSTEES_IN_BEAST) ||
(authInfo->p.numVisibilityTrusteesAssigned > MAX_VISIBILITY_TRUSTEES_IN_BEAST) )
{
storeBuffer = NULL;
SetErrno( genMsg, zERR_BEAST_CORRUPTED );
}
else
{
/*
* If there are visibility overflow beasts that will need to
* be fixed up then set the version to a previous value.
*/
if (authInfo->p.visibilityOverflow != zINVALID_ZID)
{
authInfo->p.version = CURRENT_AUTH_VERSION - 1;
}
/* Convert ACL entries */
if (authInfo->p.numTrusteesAssigned > 0)
{
oldACLEntry = (V1_ACLEntry_s *)storeBuffer;
convertCount = 0;
for (count = 0; count < authInfo->p.numTrusteesAssigned; count++)
{
#if zNETWARE
/*
* If there is an error converting then the entry is ignored.
*/
if (COMN_MapNDSIDToGUID(&status, oldACLEntry->trusteeID,
&authInfo->p.ACL[convertCount].trusteeID) == zOK)
{
authInfo->p.ACL[convertCount].rights = oldACLEntry->rights;
authInfo->p.ACL[convertCount].attributes =
oldACLEntry->attributes;
convertCount++;
}
#if NSS_DEBUG IS_ENABLED
else
{
DBG_DebugPrintf(LRED, "VAUTH_UnpackAuthBeast: Ignored an invalid ACL entry\n");
}
#endif
#endif
#if zLINUX
status = zFAILURE;
printk(KERN_ALERT "VAUTH_UnpackAuthBeast: Ignored an old-version ACL entry\n");
#endif
oldACLEntry++;
}
authInfo->p.numTrusteesAssigned = convertCount;
storeBuffer = (BYTE *)oldACLEntry ;
}
/* Convert Visibility entries */
if (authInfo->p.numVisibilityTrusteesAssigned > 0)
{
oldVisEntry = (V1_VisEntry_s *)storeBuffer;
convertCount = 0;
for (count = 0; count < authInfo->p.numVisibilityTrusteesAssigned;
count++)
{
#if zNETWARE
if (COMN_MapNDSIDToGUID(&status, oldVisEntry->trusteeID,
&authInfo->p.visibilityList[convertCount].trusteeID) == zOK)
{
authInfo->p.visibilityList[convertCount].count =
oldVisEntry->count;
#if NSS_DEBUG IS_ENABLED
DBG_DebugPrintf(LBLUE,
"VAUTH_UnpackAuthBeast: Valid visibility entry. ID=%x GUID=%x-%x\n",
oldVisEntry->trusteeID,
authInfo->p.visibilityList[convertCount].trusteeID.timeLow,
authInfo->p.visibilityList[convertCount].trusteeID.node[5]);
#endif
convertCount++;
}
#if NSS_DEBUG IS_ENABLED
else
{
DBG_DebugPrintf(LRED,
"VAUTH_UnpackAuthBeast: Ignored an invalid visibility entry. ID=%x\n",
oldVisEntry->trusteeID);
}
#endif
#endif
#if zLINUX
status = zFAILURE;
printk(KERN_ALERT "VAUTH_UnpackAuthBeast: Ignored an old-version visibility entry\n");
#endif
oldVisEntry++;
}
authInfo->p.numVisibilityTrusteesAssigned = convertCount;
storeBuffer = (BYTE *)oldVisEntry ;
/* Sort the entries */
for (count = 1; count < authInfo->p.numVisibilityTrusteesAssigned;
count++)
{
for (inner = 0;
inner < authInfo->p.numVisibilityTrusteesAssigned - count; inner++)
{
if (LB_GUIDCompare(&authInfo->p.visibilityList[inner].trusteeID,
&authInfo->p.visibilityList[inner + 1].trusteeID) > 0)
{
temp = authInfo->p.visibilityList[inner];
authInfo->p.visibilityList[inner] =
authInfo->p.visibilityList[inner + 1];
authInfo->p.visibilityList[inner + 1] = temp;
}
}
}
}
}
}
else
{
len = sizeof(ZASPersistentAuthInfo_s) -
(sizeof(authInfo->p.ACL) + sizeof(authInfo->p.visibilityList));
memcpy(&authInfo->p, storeBuffer, len);
storeBuffer += len;
/* Bug#377670 - Need to place the data into authInfo->p before testing
that it has legal values. Before counts would be 0 always so we
did not catch corrupt beasts and then would corrupt lots of memory. */
if( (authInfo->p.numTrusteesAssigned > MAX_TRUSTEES_IN_BEAST) ||
(authInfo->p.numVisibilityTrusteesAssigned > MAX_VISIBILITY_TRUSTEES_IN_BEAST) )
{
storeBuffer = NULL;
SetErrno( genMsg, zERR_BEAST_CORRUPTED );
}
else
{
len = sizeof(ACLEntry_s) * authInfo->p.numTrusteesAssigned;
memcpy(&authInfo->p.ACL, storeBuffer, len);
storeBuffer += len;
len = sizeof(ACLEntry_s) * authInfo->p.numVisibilityTrusteesAssigned;
memcpy(&authInfo->p.visibilityList, storeBuffer, len);
storeBuffer += len;
}
/* The following lines are for the cluster file system read only vol */
if ((authBeast->AUTHvolume->VOLenabledAttributes & zATTR_READONLY) &&
(!(genMsg->flags & UPDATE_EXISTING_BEAST)))
{
authInfo->p.signature = 0;
authInfo->p.restartCount = 0;
authInfo->p.cacheIndex = INVALID_EACL_CACHE_INDEX;
}
}
UNX_LATCH(&authInfo->authLatch);
RTN_PTR(storeBuffer);
}
///****************************************************************************
// * findVisTrustee
// * Use a binary search to find a visibility trustee in an overflow beast.
// * Returns the index into the overflow beast. If the entry is not found
// * it returns the next higher value (the place to insert it);
// ****************************************************************************/
//NINT findVisTrustee(
// ZasVisOverflowBeast_s *overflowBeast;
// NINT trusteeID)
//{
// LONG midID;
// NINT start;
// NINT end;
// NINT mid;
//
// start = 0;
// end = overflowBeast->p.numEntries;
// do
// {
// mid = (start + end) / 2;
// midID = overflowBeast->vis[mid].trusteeID;
// if(trusteeID <= midID)
// {
// if (trusteeID == midID)
// return mid;
// end = mid;
// }
// else
// {
// start = mid + 1;
// }
// } while(start < end);
//
// return end; /* not found */
//}
#if (CURRENT_BEAST_VERSION != BEAST_VERSION_3)
#error "Check to see if the conversion code below is still needed. It was"
#error "used to convert beast version 1 to beast version 2."
#endif
/****************************************************************************
*
* This routine converts an ACL overflow beast from beast version 1 to
* beast version 2. It is done here instead of the unpack routine because
* one beast may create many. The unpack routine has already converted the
* IDs to GUIDs.
*
****************************************************************************/
STATUS ZAS_ConvertACLFromVersionOne (
GeneralMsg_s *genMsg,
ZasAclOverflowBeast_s *overflowBeast)
{
NINT numToMove;
ZasAclOverflowBeast_s *newOverflowBeast;
STATUS status;
Xaction_s *xaction;
BOOL needToDownLatch = FALSE;
if (overflowBeast->ACLObeastVersion > BEAST_VERSION_1)
{
zASSERT(overflowBeast->p.numEntries <= MAX_ACL_OVERFLOW_ENTRIES);
return zOK;
}
/*
* This is an older beast that could hold more entries. It
* will now be split up into multiple beasts if it is too big
* for the current version. This code can be removed when we
* are no longer converting from version 1 beasts.
*/
ASSERT_LATCH(&overflowBeast->ACLObeastLatch);
if (!IS_XLATCHED(&overflowBeast->ACLObeastLatch))
{
UP_LATCH(&overflowBeast->ACLObeastLatch);
if (overflowBeast->p.numEntries <= MAX_ACL_OVERFLOW_ENTRIES)
{ /* We now don't need to convert -- it was done by someone else while we were uplatching */
DOWN_LATCH(&overflowBeast->ACLObeastLatch);
return zOK;
}
needToDownLatch = TRUE;
}
#if NSS_DEBUG IS_ENABLED
DBG_DebugPrintf(LBLUE,"After on-the-fly: ACL overflow\n");
#endif
xaction = COMN_BeginXLocal(overflowBeast);
/* Create new beasts to handle the excess */
while (overflowBeast->p.numEntries > MAX_ACL_OVERFLOW_ENTRIES)
{
newOverflowBeast = (ZasAclOverflowBeast_s *)BST_create(genMsg,
zFTYPE_ZAS_ACL_OVERFLOW, overflowBeast->ACLOvolume, xaction);
if (overflowBeast == NULL)
{
goto cleanup;
}
numToMove = overflowBeast->p.numEntries % MAX_ACL_OVERFLOW_ENTRIES;
if (numToMove == 0)
{
numToMove = MAX_ACL_OVERFLOW_ENTRIES;
}
newOverflowBeast->numAlloced = numToMove;
/* free the memory alloced by the BST_create */
free(newOverflowBeast->acl);
newOverflowBeast->acl =
malloc(newOverflowBeast->numAlloced * sizeof (ACLEntry_s));
if (newOverflowBeast->acl == NULL)
{
SetErrno(genMsg, zERR_NO_MEMORY);
UNX_LATCH(&newOverflowBeast->ACLObeastLatch);
BST_free(newOverflowBeast);
goto cleanup;
}
overflowBeast->p.numEntries -= numToMove;
/* insert entries in the new beast */
memcpy(newOverflowBeast->acl,
&overflowBeast->acl[overflowBeast->p.numEntries],
sizeof(ACLEntry_s) * numToMove);
newOverflowBeast->ACLObstState |= BST_STATE_NEW;
newOverflowBeast->p.numEntries = numToMove;
/* fix up the links */
newOverflowBeast->p.nextOverflowZid =
overflowBeast->p.nextOverflowZid;
overflowBeast->p.nextOverflowZid = newOverflowBeast->ACLOzid;
/* write out the new beast */
COMN_MARK_BEAST_XLOCAL(&newOverflowBeast->ACLOroot, xaction);
status = COMN_ForceBeastWrite(genMsg, newOverflowBeast, xaction);
BEASTHASH_Insert(&newOverflowBeast->ACLOroot);
COMN_UnlatchAndRelease(&newOverflowBeast, XLATCHED);
if (status != zOK)
{
goto cleanup;
}
}
/* update the original beast */
COMN_MARK_BEAST_XLOCAL(&overflowBeast->ACLOroot, xaction);
status = COMN_ForceBeastWrite(genMsg, overflowBeast, xaction);
if (status != zOK)
{
goto cleanup;
}
COMN_EndXLocal(overflowBeast, &xaction);
if (needToDownLatch)
{
DOWN_LATCH(&overflowBeast->ACLObeastLatch);
}
return zOK;
cleanup:
COMN_EndXLocal(overflowBeast, &xaction);
if (needToDownLatch)
{
DOWN_LATCH(&overflowBeast->ACLObeastLatch);
}
return zFAILURE;
}
#if (CURRENT_BEAST_VERSION != BEAST_VERSION_3)
#error "Check to see if the conversion code below is still needed. It was"
#error "used to convert beast version 1 to beast version 2."
#endif
/****************************************************************************
*
* This routine converts all VIS overflow beasts on this auth beast
* from beast version 1 to beast version 2. It is done here instead of the
* unpack routine because one beast may create many. The unpack routine has
* already converted the IDs to GUIDs.
*
* The routine reads in all of visibility entries from the old beasts, sorts
* them and them writes them out again in the new format.
*
* If there is no transaction active then one is created.
*
****************************************************************************/
STATUS ZAS_ConvertVisFromVersionOne (
GeneralMsg_s *genMsg,
Xaction_s *passedInXaction,
AuthBeast_s *authBeast)
{
ZasVisOverflowBeast_s *overflowBeast = NULL;
ZasVisOverflowBeast_s *prevOverflowBeast = NULL;
ZASAuthorizeInfo_s *authInfo;
NINT numToMove;
NINT numMoved = 0;
NINT count;
NINT inner;
VisEntry_s *holdVis = NULL;
NINT totalEntries;
Xaction_s *xaction;
BOOL needToDownLatch = FALSE;
BOOL downAuthBeastLatch = FALSE;
Zid_t overflowZid;
VisEntry_s temp;
STATUS status;
BOOL clearForceFlag = FALSE;
authInfo = authBeast->AUTHauthInfo.zas;
if (authInfo->p.version == CURRENT_AUTH_VERSION)
{
return zOK;
}
if (!(IS_LATCHED(&authBeast->AUTHbeastLatch)))
{
/*Cannot convert visibility if we don't have a latch */
/* Do not know if we can get a latch without deadlocking if we
* come in here without a latch
*/
return zFAILURE;
}
ASSERT_LATCH(&authBeast->AUTHbeastLatch);
ASSERT_LATCH(&authInfo->authLatch);
#if NSS_DEBUG IS_ENABLED
DBG_DebugPrintf(LBLUE,"After on-the-fly: visibility overflow\n");
#endif
if (IS_XLATCHED(&authBeast->AUTHbeastLatch))
{
if (!IS_XLATCHED(&authInfo->authLatch))
{
UP_LATCH(&authInfo->authLatch);
needToDownLatch = TRUE;
}
}
else
{
if (IS_XLATCHED(&authInfo->authLatch))
{
UNX_LATCH(&authInfo->authLatch);
}
else
{
UNS_LATCH(&authInfo->authLatch);
needToDownLatch = TRUE;
}
UP_LATCH(&authBeast->AUTHbeastLatch);
downAuthBeastLatch = TRUE;
X_LATCH(&authInfo->authLatch);
}
if (authInfo->p.version == CURRENT_AUTH_VERSION)
{
/* We now don't need to convert -- it was done by someone else
* while we were uplatching */
status = zOK;
goto fixupLatchesAndReturnStatus;
}
ASSERT_XLATCH(&authBeast->AUTHbeastLatch);
ASSERT_XLATCH(&authInfo->authLatch);
if (!(authInfo->flags & ZAS_ALLOW_FORCED_WRITE))
{
authInfo->flags |= ZAS_ALLOW_FORCED_WRITE;
clearForceFlag = TRUE;
}
/****************************************
* Count the entries
****************************************/
totalEntries = authInfo->p.numVisibilityTrusteesAssigned;
overflowZid = authInfo->p.visibilityOverflow;
while (overflowZid != zINVALID_ZID)
{
/* get the next overflow beast */
overflowBeast = ZAS_LookupOverflowBeast(genMsg, authBeast->AUTHvolume,
overflowZid, SLATCHED, zFTYPE_ZAS_VIS_OVERFLOW);
if (overflowBeast == NULL)
{ /* error */
goto cleanup;
}
totalEntries += overflowBeast->p.numEntries;
overflowZid = overflowBeast->p.nextOverflowZid;
COMN_UnlatchAndRelease(&overflowBeast, SLATCHED);
}
/* Get the needed memory block */
if (totalEntries != 0)
{
holdVis = malloc(totalEntries * sizeof (VisEntry_s));
if (holdVis == NULL)
{
SetErrno(genMsg, zERR_NO_MEMORY);
goto cleanup;
}
}
/****************************************
* Read all of the entries into memory
****************************************/
/* read the entries from the main beast */
for (numToMove = 0; numToMove < authInfo->p.numVisibilityTrusteesAssigned;
numToMove++)
{
if (LB_GUIDCompare(&authInfo->p.visibilityList[numToMove].trusteeID,
&zINVALID_USERID) != 0)
{
holdVis[numMoved++] = authInfo->p.visibilityList[numToMove];
}
#if NSS_DEBUG IS_ENABLED
else
{
DBG_DebugPrintf(LRED, "ZAS_ConvertVisFromVersionOne: Ignored an invalid visibility entry\n");
}
#endif
}
/* read the entries from the overflow beasts */
overflowZid = authInfo->p.visibilityOverflow;
while (overflowZid != zINVALID_ZID)
{
/* get the next overflow beast */
overflowBeast = ZAS_LookupOverflowBeast(genMsg, authBeast->AUTHvolume,
overflowZid, SLATCHED, zFTYPE_ZAS_VIS_OVERFLOW);
if (overflowBeast == NULL)
{ /* error */
goto cleanupFree;
}
for (numToMove = 0; numToMove < overflowBeast->p.numEntries;
numToMove++)
{
if (LB_GUIDCompare(&overflowBeast->vis[numToMove].trusteeID,
&zINVALID_USERID) != 0)
{
holdVis[numMoved++] = overflowBeast->vis[numToMove];
}
#if NSS_DEBUG IS_ENABLED
else
{
DBG_DebugPrintf(LRED, "ZAS_ConvertVisFromVersionOne: Ignored an invalid overflow visibility entry\n");
}
#endif
}
overflowZid = overflowBeast->p.nextOverflowZid;
COMN_UnlatchAndRelease(&overflowBeast, SLATCHED);
}
totalEntries = numMoved;
/****************************************
* Sort the entries
****************************************/
for (count = 1; count < totalEntries; count++)
{
for (inner = 0;
inner < totalEntries - count; inner++)
{
if (LB_GUIDCompare(&holdVis[inner].trusteeID,
&holdVis[inner + 1].trusteeID) > 0)
{
temp = holdVis[inner];
holdVis[inner] = holdVis[inner + 1];
holdVis[inner + 1] = temp;
}
}
}
//#if NSS_DEBUG IS_ENABLED
// DBG_DebugPrintf(YELLOW, "Convert visibility structure after sorting:\n");
// for (count=0; count < totalEntries; count++)
// {
// DBG_DebugPrintf(LBLUE, MSGNot(" (%d) Trustee: %08x-%04x-%04x-%02x%02x-%02x%02x%02x%02x%02x%02x Count: %d\n"),
// count,
// holdVis[count].trusteeID.timeLow,
// holdVis[count].trusteeID.timeMid,
// holdVis[count].trusteeID.timeHighAndVersion,
// holdVis[count].trusteeID.clockSeqHighAndReserved,
// holdVis[count].trusteeID.clockSeqLow,
// holdVis[count].trusteeID.node[0],
// holdVis[count].trusteeID.node[1],
// holdVis[count].trusteeID.node[2],
// holdVis[count].trusteeID.node[3],
// holdVis[count].trusteeID.node[4],
// holdVis[count].trusteeID.node[5],
// holdVis[count].count);
// }
//#endif
/****************************************
* Write out the new overflow beasts
****************************************/
xaction = (passedInXaction == NULL) ? COMN_BeginXLocal(authBeast) :
passedInXaction;
numMoved = 0;
/* fill up the main beast */
authInfo->p.numVisibilityTrusteesAssigned =
totalEntries > MAX_VISIBILITY_TRUSTEES_IN_BEAST ?
MAX_VISIBILITY_TRUSTEES_IN_BEAST :
totalEntries;
for (numToMove = 0; numToMove < authInfo->p.numVisibilityTrusteesAssigned;
numToMove++)
{
authInfo->p.visibilityList[numToMove] = holdVis[numMoved++];
}
/* Remove the old beasts */
overflowZid = authInfo->p.visibilityOverflow;
while (overflowZid != zINVALID_ZID)
{
/* get the next overflow beast */
overflowBeast = ZAS_LookupOverflowBeast(genMsg, authBeast->AUTHvolume,
overflowZid, XLATCHED, zFTYPE_ZAS_VIS_OVERFLOW);
if (overflowBeast == NULL)
{ /* error */
goto cleanupXaction;
}
overflowZid = overflowBeast->p.nextOverflowZid;
if (BST_delete(genMsg, NULL, overflowBeast, NULL, NULL, xaction,
FALSE, TRUE) != zOK)
{
zASSERT("Failed to remove old beasts during conversion" == 0);
}
COMN_UnlatchAndRelease(&overflowBeast, XLATCHED);
}
authInfo->p.visibilityOverflow = zINVALID_ZID;
/* create the new beasts */
while (numMoved < totalEntries)
{
overflowBeast = (ZasVisOverflowBeast_s *)BST_create(genMsg,
zFTYPE_ZAS_VIS_OVERFLOW, authBeast->AUTHvolume, xaction);
if (overflowBeast == NULL)
{
goto cleanupXaction;
}
numToMove = ((totalEntries - numMoved) >= MAX_VIS_OVERFLOW_ENTRIES) ?
MAX_VIS_OVERFLOW_ENTRIES : totalEntries - numMoved;
overflowBeast->numAlloced = numToMove;
free(overflowBeast->vis); /* this was alloced by the constructor */
overflowBeast->vis =
malloc(overflowBeast->numAlloced * sizeof (VisEntry_s));
if (overflowBeast->vis == NULL)
{
SetErrno(genMsg, zERR_NO_MEMORY);
UNX_LATCH(&overflowBeast->VISObeastLatch);
BST_free(overflowBeast);
goto cleanupXaction;
}
/* insert entries in the new beast */
memcpy(overflowBeast->vis, &holdVis[numMoved],
sizeof(VisEntry_s) * numToMove);
numMoved += numToMove;
overflowBeast->VISObstState |= BST_STATE_NEW;
overflowBeast->p.numEntries = numToMove;
/* fix up the links */
overflowBeast->p.nextOverflowZid = zINVALID_ZID;
if (prevOverflowBeast == NULL)
{ /* link to the main beast */
authInfo->p.visibilityOverflow = overflowBeast->VISOzid;
}
else
{
prevOverflowBeast->p.nextOverflowZid = overflowBeast->VISOzid;
/* write out the previous beast */
BEASTHASH_Insert(&prevOverflowBeast->VISOroot);
COMN_MARK_BEAST_XLOCAL(&prevOverflowBeast->VISOroot, xaction);
COMN_ForceBeastWrite(genMsg, prevOverflowBeast, xaction);
zASSERT(prevOverflowBeast->VISOuseCount > 1);
COMN_UnlatchAndRelease(&prevOverflowBeast, XLATCHED);
}
prevOverflowBeast = overflowBeast;
}
/* write out the final beast if we need to */
if (prevOverflowBeast != NULL)
{
BEASTHASH_Insert(&prevOverflowBeast->VISOroot);
COMN_MARK_BEAST_XLOCAL(&prevOverflowBeast->VISOroot, xaction);
COMN_ForceBeastWrite(genMsg, prevOverflowBeast, xaction);
zASSERT(prevOverflowBeast->VISOuseCount > 1);
COMN_UnlatchAndRelease(&prevOverflowBeast, XLATCHED);
}
/* write out the main beast */
authInfo->p.version = CURRENT_AUTH_VERSION;
COMN_MARK_BEAST_XLOCAL(&authBeast->AUTHroot, xaction);
COMN_ForceBeastWrite(genMsg, authBeast, xaction);
/* If the transaction was started in this routine then end it */
if (passedInXaction == NULL)
{
COMN_EndXLocal(authBeast, &xaction);
}
if (holdVis != NULL)
{
free(holdVis);
}
status = zOK;
fixupLatchesAndReturnStatus:
if (clearForceFlag)
{
authInfo->flags &= ~ZAS_ALLOW_FORCED_WRITE;
}
if (downAuthBeastLatch)
{
UNX_LATCH(&authInfo->authLatch);
DOWN_LATCH(&authBeast->AUTHbeastLatch);
if (needToDownLatch)
{
S_LATCH(&authInfo->authLatch);
}
else
{
X_LATCH(&authInfo->authLatch);
}
}
else
{
if (needToDownLatch)
{
DOWN_LATCH(&authInfo->authLatch);
}
}
return status;
cleanupXaction:
/* If the transaction was started in this routine then end it */
if (passedInXaction == NULL)
{
COMN_EndXLocal(authBeast, &xaction);
}
cleanupFree:
if (holdVis != NULL)
{
free(holdVis);
}
cleanup:
status = zFAILURE;
goto fixupLatchesAndReturnStatus;
}
/****************************************************************************
* This routine will find a trustee and return a pointer to the visibility
* info.
*
* output: returnBeast - The beast where the entry is found or where it
* should be inserted. Returned opened and latched. If it is
* null then there are no overflow beasts OR we got an error
* on lookup of an overflow beast!
*
* entryPtr - A pointer to the found entry. If the trustee is not
* found then then a null is returned.
*
* entry - The index into either the authInfo in the main beast or
* the visibility info in the overflow beast.
* If an entry is found then it points to the entry, or it points
* to the location where a new entry should be inserted. The
* insertion point is the place to insert and not a free 'slot'.
* IDs are kept in order so everything must be memmoved and etc.
*
* parentZid - the zid of the parent beast. If invalid then the
* parent was the main beast.
*
****************************************************************************/
STATUS ZAS_FindVisibilityTrustee(
GeneralMsg_s *genMsg,
AuthBeast_s *authBeast,
#if (CURRENT_BEAST_VERSION != BEAST_VERSION_3)
#error "Check to see if the xaction below is still needed."
#endif
Xaction_s *xaction,
UserID_t *trusteeID,
NINT latchType,
VisEntry_s **entryPtr,
NINT *entry,
ZasVisOverflowBeast_s **returnBeast,
Zid_t *parentZid)
{
ZASAuthorizeInfo_s *authInfo;
ZasVisOverflowBeast_s *overflowBeast;
ZasVisOverflowBeast_s *prevOverflowBeast = NULL;
Zid_t overflowZid;
UserID_t midID;
NINT start;
NINT end;
NINT mid;
ASSERT_MPKNSS_LOCK();
ENTER(TAUTH, ZAS_FindVisibilityTrustee);
authInfo = authBeast->AUTHauthInfo.zas;
ASSERT_LATCH(&authInfo->authLatch);
*returnBeast = NULL;
*parentZid = zINVALID_ZID;
*entryPtr = NULL;
#if (CURRENT_BEAST_VERSION != BEAST_VERSION_3)
#error "Check to see if the beastVersion code below is still needed."
#endif
/* BEGINNING OF BEAST VERSION ONE CONVERSION CODE */
if (ZAS_ConvertVisFromVersionOne(genMsg, xaction, authBeast) != zOK)
{
RTN_STATUS(zFAILURE);
}
/* END OF BEAST VERSION ONE CONVERSION CODE */
/* search the main beast for the visibility trustee */
for (*entry=0; *entry < authInfo->p.numVisibilityTrusteesAssigned;
(*entry)++)
{
if (LB_GUIDCompare(&authInfo->p.visibilityList[*entry].trusteeID,
trusteeID) > 0)
{
*entryPtr = NULL;
RTN_STATUS(zOK);
}
if (LB_GUIDCompare(&authInfo->p.visibilityList[*entry].trusteeID,
trusteeID) == 0)
{
*entryPtr = &authInfo->p.visibilityList[*entry];
RTN_STATUS(zOK);
}
}
overflowBeast = NULL;
/* search the overflow beasts for the visibility trustee */
overflowZid = authInfo->p.visibilityOverflow;
while (overflowZid != zINVALID_ZID)
{ /* find an overflow beast with an open entry */
/* get the next overflow beast */
prevOverflowBeast = overflowBeast;
overflowBeast = ZAS_LookupOverflowBeast(genMsg, authBeast->AUTHvolume,
overflowZid, latchType, zFTYPE_ZAS_VIS_OVERFLOW);
if (overflowBeast == NULL)
{ /*
* Error -- fix up the beast so it looks like it did not have
* another overflow (simple self-healing).
*/
zASSERT("Error looking up visibility overflow beast" == NULL);
*returnBeast = prevOverflowBeast;
if (prevOverflowBeast)
{
prevOverflowBeast->p.nextOverflowZid = zINVALID_ZID;
}
else
{
authInfo->p.visibilityOverflow = zINVALID_ZID;
}
*entryPtr = NULL;
RTN_STATUS(zOK);
}
if (prevOverflowBeast != NULL)
{
COMN_UnlatchAndRelease(&prevOverflowBeast, latchType);
}
*entry = end = overflowBeast->p.numEntries;
if ( end == 0 )
{ /* not found -- return the insertion point */
/* *entry = end; Already set */
*returnBeast = overflowBeast;
*entryPtr = NULL; /* not found */
RTN_STATUS(zOK);
}
if (LB_GUIDCompare(trusteeID, &overflowBeast->vis[end-1].trusteeID) <= 0)
{ /* it should fall in this record */
/* use a binary search to find the entry */
start = 0;
do
{
mid = (start + end) / 2;
midID = overflowBeast->vis[mid].trusteeID;
if(LB_GUIDCompare(trusteeID, &midID) <= 0)
{
if (LB_GUIDCompare(trusteeID, &midID) == 0)
{ /* found the trustee entry */
*returnBeast = overflowBeast;
*entry = mid;
*entryPtr = &overflowBeast->vis[mid];
RTN_STATUS(zOK);
}
end = mid;
}
else
{
start = mid + 1;
}
} while(start < end);
/* not found -- return the insertion point */
*entry = end;
*returnBeast = overflowBeast;
*entryPtr = NULL; /* not found */
RTN_STATUS(zOK);
}
*parentZid = overflowZid;
overflowZid = overflowBeast->p.nextOverflowZid;
zASSERT((overflowZid == zINVALID_ZID) ||
(overflowBeast->p.numEntries == MAX_VIS_OVERFLOW_ENTRIES));
}
*returnBeast = overflowBeast;
*entryPtr = NULL;
RTN_STATUS(zOK);
}
/****************************************************************************
* This routines will get the visibility entries for a single auth Beast.
*
* Parameter:
* genMsg
* authBeast The beast we will search for visibility
* maxEntries The maximum number of entries that can be returned
* visEntries A buffer that will be filled in this routine
* numReturned The number of
****************************************************************************/
STATUS ZAS_GetVisibilityEntries(
GeneralMsg_s *genMsg,
AuthBeast_s *authBeast, /* The beast we will search for visibility */
NINT maxEntries, /* The maximum number of entries that can be returned */
VisEntry_s *visEntries, /* A buffer that will be filled in this routine */
NINT *numReturned) /* The number of entries being returned.
If there are more entries than space
in the buffer the return count will be
-1, and the buffer will be filled */
{
ZASAuthorizeInfo_s *authInfo;
ZasVisOverflowBeast_s *overflowBeast;
Zid_t overflowZid;
NINT count;
ENTER(TAUTH, ZAS_GetVisibilityEntries);
authInfo = authBeast->AUTHauthInfo.zas;
S_LATCH(&authInfo->authLatch);
/* search the main beast for the visibility trustee */
for (*numReturned = 0;
*numReturned < authInfo->p.numVisibilityTrusteesAssigned;
(*numReturned)++)
{
if (*numReturned >= maxEntries)
{
*numReturned = -1;
goto finished;
}
visEntries[*numReturned] = authInfo->p.visibilityList[*numReturned];
}
/* search the overflow beasts for the visibility trustee */
overflowZid = authInfo->p.visibilityOverflow;
while (overflowZid != zINVALID_ZID)
{
/* get the next overflow beast */
overflowBeast = ZAS_LookupOverflowBeast(genMsg, authBeast->AUTHvolume,
overflowZid, SLATCHED, zFTYPE_ZAS_VIS_OVERFLOW);
if (overflowBeast == NULL)
{ /* error */
UNS_LATCH(&authInfo->authLatch);
RTN_STATUS(zFAILURE);
}
for (count = 0; count < overflowBeast->p.numEntries; count++)
{
if (*numReturned >= maxEntries)
{
COMN_UnlatchAndRelease(&overflowBeast, SLATCHED);
*numReturned = -1;
goto finished;
}
visEntries[(*numReturned)++] = overflowBeast->vis[count];
}
overflowZid = overflowBeast->p.nextOverflowZid;
COMN_UnlatchAndRelease(&overflowBeast, SLATCHED);
}
finished:
UNS_LATCH(&authInfo->authLatch);
RTN_STATUS(zOK);
}
/****************************************************************************
* This routine will add visibility rights up the tree for an object.
*
****************************************************************************/
AuthBeast_s *ZAS_InternalMakeItVisible(
GeneralMsg_s *genMsg,
AuthBeast_s *authBeast,
Volume_s *volume,
UserID_t *trusteeIDList,
NINT *trusteeCount,
FixVisibPLog_s *pLogLocPtrList)
{
Zid_t overflowZid = zINVALID_ZID;
Zid_t dummyZid;
ZASAuthorizeInfo_s *authInfo;
Zid_t parentZID = authBeast->AUTHzid;
AuthBeast_s *pBeast;
VisEntry_s *visEntry;
VisEntry_s holdEntry;
VisEntry_s tempEntry;
ZasVisOverflowBeast_s *overflowBeast;
ZasVisOverflowBeast_s *parentBeast;
NINT entryIndex;
BOOL writeMainBeast = FALSE;
Xaction_s *xaction;
PurgeLogMsg_s purgeLogMsg;
UserID_t *trusteeID = trusteeIDList;
FixVisibPLog_s *pLogLocPtr = pLogLocPtrList;
NINT i;
ASSERT_MPKNSS_LOCK();
authInfo = authBeast->AUTHauthInfo.zas;
X_LATCH(&authInfo->authLatch);
authInfo->flags |= ZAS_ALLOW_FORCED_WRITE;
//#if NSS_DEBUG IS_ENABLED
//DBG_DebugPrintf(GREEN, MSGNot("\nEntering Insert Visibility -- Trustee: %x"), *trusteeID);
//DEBUG_Display_Visibility(authBeast);
//#endif
/** NOTE: It is ok to do a forcebeastwrite on the overflow beast, and
** unlatch the beast before the transaction ends, because
** we have a latch on the auth beast until after the xaction
** ends, and no one can get the overflow beast without first
** getting a latch on the auth beast.
**/
for (i = 0; i < *trusteeCount; )
{
xaction = COMN_BeginXLocal(authBeast);
zASSERT(pLogLocPtr != NULL);
SETUP_FIX_VISIBILITY_PURGE_LOG(&purgeLogMsg, pLogLocPtr,
VIS_ACTION_ADD, parentZID, trusteeID);
if (authBeast->AUTHcomnVolOps.VOL_removePurgeLogEntry(
genMsg, authBeast->AUTHvolume,
PLOG_FIX_VISIBILITY, &purgeLogMsg, xaction) != zOK)
{
goto errorTryNextTrustee;
}
holdEntry.trusteeID = zINVALID_USERID;
if (ZAS_FindVisibilityTrustee(genMsg, authBeast, xaction, trusteeID,
XLATCHED, &visEntry, &entryIndex,
&overflowBeast, &dummyZid) != zOK)
{
/* error */
goto errorTryNextTrustee;
}
if (visEntry != NULL)
{ /* if it is found */
visEntry->count++;
if (overflowBeast == NULL)
{ /* in the main beast */
COMN_MARK_BEAST_XLOCAL(&authBeast->AUTHroot, xaction);
COMN_ForceBeastWrite(genMsg, authBeast, xaction);
}
else
{ /* in an overflow beast */
COMN_MARK_BEAST_XLOCAL(&overflowBeast->VISOroot, xaction);
COMN_ForceBeastWrite(genMsg, overflowBeast, xaction);
COMN_UnlatchAndRelease(&overflowBeast, XLATCHED);
}
//#if NSS_DEBUG IS_ENABLED
//DBG_DebugPrintf(GREEN, MSGNot("\n(1)Exiting Insert Visibility -- Trustee: %x"), *trusteeID);
//DEBUG_Display_Visibility(authBeast);
//#endif
goto visibilityDoneForThisTrustee;
}
else
{ /* add a new entry */
if (overflowBeast == NULL)
{ /* the new entry should go in the main beast */
zASSERT(authInfo->p.numVisibilityTrusteesAssigned <=
MAX_VISIBILITY_TRUSTEES_IN_BEAST);
zASSERT(entryIndex <= authInfo->p.numVisibilityTrusteesAssigned);
if (authInfo->p.numVisibilityTrusteesAssigned ==
MAX_VISIBILITY_TRUSTEES_IN_BEAST)
{ /* the main beast is full */
overflowZid = authInfo->p.visibilityOverflow;
if (entryIndex == MAX_VISIBILITY_TRUSTEES_IN_BEAST)
{ /* the new entry should go in the overflow */
holdEntry.trusteeID = *trusteeID;
holdEntry.count = 1;
}
else
{ /* the new entry goes in the main beast */
/* save the last entry to move it to the next beast */
holdEntry = authInfo->p.visibilityList[
MAX_VISIBILITY_TRUSTEES_IN_BEAST - 1];
memmove(&authInfo->p.visibilityList[entryIndex + 1],
&authInfo->p.visibilityList[entryIndex],
((MAX_VISIBILITY_TRUSTEES_IN_BEAST - 1) -
entryIndex) * sizeof(VisEntry_s));
authInfo->p.visibilityList[entryIndex].trusteeID =
*trusteeID;
authInfo->p.visibilityList[entryIndex].count = 1;
writeMainBeast = TRUE;
}
/* insert holdEntry at the front of the overflow beast */
entryIndex = 0;
/* open the overflow beast if needed */
if (overflowZid != zINVALID_ZID)
{
overflowBeast = ZAS_LookupOverflowBeast(genMsg,
authBeast->AUTHvolume, overflowZid,
XLATCHED, zFTYPE_ZAS_VIS_OVERFLOW);
if (overflowBeast == NULL)
{ /* error */
goto errorTryNextTrustee;
}
}
}
else
{
zASSERT(overflowZid == zINVALID_ZID);
memmove(&authInfo->p.visibilityList[entryIndex+1],
&authInfo->p.visibilityList[entryIndex],
(authInfo->p.numVisibilityTrusteesAssigned - entryIndex)
* sizeof(VisEntry_s));
authInfo->p.numVisibilityTrusteesAssigned++;
authInfo->p.visibilityList[entryIndex].trusteeID =
*trusteeID;
authInfo->p.visibilityList[entryIndex].count = 1;
writeMainBeast = TRUE;
}
}
else
{ /* adding an entry to the overflow beast */
overflowZid = overflowBeast->VISOzid;
holdEntry.trusteeID = *trusteeID;
holdEntry.count = 1;
}
/*
* Insert into an overflow beast.
*
* If an insert to a full overflow beast has occured then shift
* all entries in beasts that follow up one slot.
*/
while (overflowZid != zINVALID_ZID)
{ /* while there are still overflow beasts */
zASSERT(overflowBeast->p.numEntries <= MAX_VIS_OVERFLOW_ENTRIES);
zASSERT(entryIndex <= overflowBeast->p.numEntries);
overflowZid = overflowBeast->p.nextOverflowZid;
if (overflowBeast->p.numEntries == MAX_VIS_OVERFLOW_ENTRIES)
{ /* if the beast is full */
if (entryIndex < MAX_VIS_OVERFLOW_ENTRIES)
{ /* entry goes in this beast */
tempEntry = overflowBeast->vis[MAX_VIS_OVERFLOW_ENTRIES
- 1];
memmove(&overflowBeast->vis[entryIndex + 1],
&overflowBeast->vis[entryIndex],
((MAX_VIS_OVERFLOW_ENTRIES - 1) - entryIndex) *
sizeof(VisEntry_s));
overflowBeast->vis[entryIndex].trusteeID =
holdEntry.trusteeID;
overflowBeast->vis[entryIndex].count = holdEntry.count;
holdEntry = tempEntry;
}
else
{ /* entry will go in a new overflow beast */
zASSERT(overflowZid == zINVALID_ZID);
}
}
else
{ /* there is still room in the beast */
VisEntry_s *vis;
zASSERT(overflowZid == zINVALID_ZID);
if (overflowBeast->p.numEntries >=
overflowBeast->numAlloced)
{ /* we need to make the memory structure bigger */
overflowBeast->numAlloced += OVERFLOW_ALLOC_UNIT;
vis = (VisEntry_s *)realloc(overflowBeast->vis,
overflowBeast->numAlloced * sizeof (VisEntry_s));
if (vis == NULL)
{
overflowBeast->numAlloced -= OVERFLOW_ALLOC_UNIT;
SetErrno(genMsg, zERR_NO_MEMORY);
goto errorTryNextTrustee;
}
overflowBeast->vis = vis;
}
memmove(&overflowBeast->vis[entryIndex+1],
&overflowBeast->vis[entryIndex],
(overflowBeast->p.numEntries -entryIndex) *
sizeof(VisEntry_s));
overflowBeast->p.numEntries++;
overflowBeast->vis[entryIndex].trusteeID =
holdEntry.trusteeID;
overflowBeast->vis[entryIndex].count = holdEntry.count;
holdEntry.trusteeID = zINVALID_USERID;
}
/* always insert at the front after the first insert */
entryIndex = 0;
if (overflowZid != zINVALID_ZID)
{
COMN_MARK_BEAST_XLOCAL(&overflowBeast->VISOroot, xaction);
COMN_ForceBeastWrite(genMsg, overflowBeast, xaction);
COMN_UnlatchAndRelease(&overflowBeast, XLATCHED);
overflowBeast = ZAS_LookupOverflowBeast(genMsg,
authBeast->AUTHvolume, overflowZid, XLATCHED, zFTYPE_ZAS_VIS_OVERFLOW);
if (overflowBeast == NULL)
{ /* error */
goto errorTryNextTrustee;
}
}
}
/* Create a new beast if needed */
if (LB_GUIDCompare(&holdEntry.trusteeID, &zINVALID_USERID) != 0)
{
parentBeast = overflowBeast;
overflowBeast = (ZasVisOverflowBeast_s *)BST_create(genMsg,
zFTYPE_ZAS_VIS_OVERFLOW, authBeast->AUTHvolume, xaction);
if (overflowBeast == NULL)
{
if (parentBeast != NULL)
{
COMN_UnlatchAndRelease(&parentBeast, XLATCHED);
}
goto errorTryNextTrustee;
}
/* link the new beast to the ones already there */
if (parentBeast == NULL)
{ /* link to main beast */
authInfo->p.visibilityOverflow = overflowBeast->VISOzid;
writeMainBeast = TRUE;
}
else
{ /* link to another overflow beast */
parentBeast->p.nextOverflowZid = overflowBeast->VISOzid;
COMN_MARK_BEAST_XLOCAL(&parentBeast->VISOroot, xaction);
COMN_ForceBeastWrite(genMsg, parentBeast, xaction);
COMN_UnlatchAndRelease(&parentBeast, XLATCHED);
}
BEASTHASH_Insert(&overflowBeast->VISOroot);
overflowBeast->VISObstState |= BST_STATE_NEW;
overflowBeast->p.numEntries = 1;
overflowBeast->vis[0] = holdEntry;
}
if (overflowBeast != NULL)
{
COMN_MARK_BEAST_XLOCAL(&overflowBeast->VISOroot, xaction);
COMN_ForceBeastWrite(genMsg, overflowBeast, xaction);
COMN_UnlatchAndRelease(&overflowBeast, XLATCHED);
}
}
if (writeMainBeast)
{ /* if the main beast is dirty */
COMN_MARK_BEAST_XLOCAL(&authBeast->AUTHroot, xaction);
COMN_ForceBeastWrite(genMsg, authBeast, xaction);
writeMainBeast = FALSE;
}
//#if NSS_DEBUG IS_ENABLED
//DBG_DebugPrintf(GREEN, MSGNot("\n(2)Exiting Insert Visibility -- Trustee: %x"), *trusteeID);
//DEBUG_Display_Visibility(authBeast);
//#endif
if (authBeast->AUTHzid != zROOTDIR_ZID)
{
SETUP_FIX_VISIBILITY_PURGE_LOG(&purgeLogMsg, pLogLocPtr,
VIS_ACTION_ADD, authBeast->AUTHfirstParentZid, trusteeID);
if (authBeast->AUTHcomnVolOps.VOL_addPurgeLogEntry(
genMsg, authBeast->AUTHvolume,
PLOG_FIX_VISIBILITY, &purgeLogMsg, xaction) != zOK)
{
goto errorTryNextTrustee;
}
}
trusteeID++;
pLogLocPtr++;
i++;
COMN_EndXLocal(authBeast, &xaction);
continue;
errorTryNextTrustee:
errPrintf(WHERE, Module, 713,
MSG("Error adding visibility for a trustee.\n", 1193));
visibilityDoneForThisTrustee:
(*trusteeCount)--;
*trusteeID = trusteeIDList[*trusteeCount];
*pLogLocPtr = pLogLocPtrList[*trusteeCount];
COMN_EndXLocal(authBeast, &xaction);
continue;
}
xaction = COMN_BeginXLocal(authBeast);
VOL_insertEFLEntry(genMsg, &authBeast->AUTHroot,
EFL_FILE_STATE_MODIFY_METADATA, NULL, xaction);
COMN_EndXLocal(authBeast, &xaction);
if ((authBeast->AUTHzid == zROOTDIR_ZID) || (*trusteeCount == 0))
{
goto doneFixingVisibility;
}
parentZID = authBeast->AUTHfirstParentZid;
/* We do not want a yield between the UNX_LATCH of authBeast and
* X_LATCH request of the parent Beast below. Hence we look
* up the parent beast first in unlatched mode and then later
* request a latch on it
*
* This routine's calling function has to guarantee that when we
* return from here, the first thing we do is request a latch
* on the returned pBeast, without any yields in between
*/
pBeast = (AuthBeast_s *)BEASTHASH_LookupByZid(genMsg, volume,
parentZID, NOTLATCHED);
if (pBeast == NULL)
{ /* error */
SetErrno(genMsg, zERR_UNABLE_TO_OPEN_BEAST);
goto errorCleanup;
}
authInfo->flags &= ~ZAS_ALLOW_FORCED_WRITE;
UNX_LATCH(&authInfo->authLatch);
UNX_LATCH(&authBeast->AUTHbeastLatch);
return pBeast;
errorCleanup:
errPrintf(WHERE, Module, 713,
MSG("Error adding visibility for trustees just added\n", 986));
doneFixingVisibility:
authInfo->flags &= ~ZAS_ALLOW_FORCED_WRITE;
UNX_LATCH(&authInfo->authLatch);
COMN_UnlatchAndRelease(&authBeast, XLATCHED);
return NULL;
}
/****************************************************************************
*
* This routine will setup to remove visibility up the tree
*
***************************************************************************/
AuthBeast_s *ZAS_InternalRemoveVisibility(
GeneralMsg_s *genMsg,
AuthBeast_s *authBeast,
Volume_s *volume,
UserID_t *trusteeIDList,
NINT *trusteeCount,
FixVisibPLog_s *pLogLocPtrList)
{
Zid_t parentZID = authBeast->AUTHzid;
Zid_t overflowZid;
Zid_t overflowParentZid;
ZASAuthorizeInfo_s *authInfo;
VisEntry_s *VisEntry;
ZasVisOverflowBeast_s *overflowBeast;
ZasVisOverflowBeast_s *parentBeast;
NINT entryIndex;
BOOL writeMainBeast = FALSE;
Xaction_s *xaction;
PurgeLogMsg_s purgeLogMsg;
AuthBeast_s *pBeast;
UserID_t *trusteeID = trusteeIDList;
FixVisibPLog_s *pLogLocPtr = pLogLocPtrList;
NINT i;
ASSERT_MPKNSS_LOCK();
authInfo = authBeast->AUTHauthInfo.zas;
X_LATCH(&authInfo->authLatch);
authInfo->flags |= ZAS_ALLOW_FORCED_WRITE;
//#if NSS_DEBUG IS_ENABLED
//DBG_DebugPrintf(GREEN, MSGNot("\nEntering Remove Visibility -- Trustee: %x"), *trusteeID);
//DEBUG_Display_Visibility(authBeast);
//#endif
/** NOTE: It is ok to do a forcebeastwrite on the overflow beast, and
** unlatch the beast before the transaction ends, because
** we have a latch on the auth beast until after the xaction
** ends, and no one can get the overflow beast without first
** getting a latch on the auth beast.
**/
for (i = 0; i < *trusteeCount; )
{
xaction = COMN_BeginXLocal(authBeast);
SETUP_FIX_VISIBILITY_PURGE_LOG(&purgeLogMsg, pLogLocPtr,
VIS_ACTION_REMOVE, parentZID, trusteeID);
if (authBeast->AUTHcomnVolOps.VOL_removePurgeLogEntry(
genMsg, authBeast->AUTHvolume,
PLOG_FIX_VISIBILITY, &purgeLogMsg, xaction) != zOK)
{
goto errorTryNextTrustee;
}
if (ZAS_FindVisibilityTrustee(genMsg, authBeast, xaction, trusteeID,
XLATCHED, &VisEntry, &entryIndex, &overflowBeast,
&overflowParentZid) != zOK)
{
goto errorTryNextTrustee;
}
if (VisEntry == NULL)
{
/* if the entry is not found then get out. This should not happen */
if (overflowBeast != NULL)
{
COMN_UnlatchAndRelease(&overflowBeast, XLATCHED);
}
SetErrno(genMsg, zERR_TRUSTEE_NOT_FOUND);
zASSERT("Trustee not found when trying to remove visibility" == 0);
goto errorTryNextTrustee;
}
/*
* if it is found
*/
if(--VisEntry->count == 0)
{ /* if the count is zero then remove the entry */
if (overflowBeast == NULL)
{ /* remove from the main beast */
authInfo->p.numVisibilityTrusteesAssigned--;
memmove(&authInfo->p.visibilityList[entryIndex],
&authInfo->p.visibilityList[entryIndex + 1],
(authInfo->p.numVisibilityTrusteesAssigned - entryIndex)
* sizeof(VisEntry_s));
overflowZid = authInfo->p.visibilityOverflow;
writeMainBeast = TRUE;
}
else
{ /* remove from an overflow beast */
overflowBeast->p.numEntries--;
memmove(&overflowBeast->vis[entryIndex],
&overflowBeast->vis[entryIndex + 1],
(overflowBeast->p.numEntries - entryIndex) *
sizeof(VisEntry_s));
overflowZid = overflowBeast->p.nextOverflowZid;
}
/*
* handle shifting entries in the overflow beasts
*/
while (overflowZid != zINVALID_ZID)
{ /* while there are overflow beasts */
parentBeast = overflowBeast;
if (parentBeast == NULL)
{
overflowParentZid = zINVALID_ZID;
}
else
{
overflowParentZid = parentBeast->VISOzid;
}
overflowBeast = ZAS_LookupOverflowBeast(genMsg,
authBeast->AUTHvolume, overflowZid, XLATCHED, zFTYPE_ZAS_VIS_OVERFLOW);
if (overflowBeast == NULL)
{
if (parentBeast)
{
COMN_UnlatchAndRelease(&parentBeast, XLATCHED);
}
goto errorTryNextTrustee;
}
if (parentBeast == NULL)
{ /* moving into the main beast */
authInfo->p.visibilityList[
MAX_VISIBILITY_TRUSTEES_IN_BEAST - 1] =
overflowBeast->vis[0];
authInfo->p.numVisibilityTrusteesAssigned++;
zASSERT(MAX_VISIBILITY_TRUSTEES_IN_BEAST ==
authInfo->p.numVisibilityTrusteesAssigned);
}
else
{ /* moving into an overflow beast */
parentBeast->vis[MAX_VIS_OVERFLOW_ENTRIES - 1] =
overflowBeast->vis[0];
parentBeast->p.numEntries++;
zASSERT(MAX_VIS_OVERFLOW_ENTRIES==parentBeast->p.numEntries);
COMN_MARK_BEAST_XLOCAL(&parentBeast->VISOroot, xaction);
COMN_ForceBeastWrite(genMsg, parentBeast, xaction);
COMN_UnlatchAndRelease(&parentBeast, XLATCHED);
}
overflowBeast->p.numEntries--;
memmove(&overflowBeast->vis[0],
&overflowBeast->vis[1],
overflowBeast->p.numEntries * sizeof(VisEntry_s));
overflowZid = overflowBeast->p.nextOverflowZid;
}
if (overflowBeast != NULL)
{
/*
* Check to see if the overflow beast should be deleted.
*/
if (overflowBeast->p.numEntries == 0)
{ /* the overflow beast is empty */
zASSERT(overflowZid == zINVALID_ZID);
if (BST_delete(genMsg, NULL, overflowBeast, NULL, NULL,
xaction, FALSE, TRUE) != zOK)
{
zASSERT("Failed to delete trustee overflow beast"==NULL);
}
COMN_UnlatchAndRelease(&overflowBeast, XLATCHED);
if (overflowParentZid == zINVALID_ZID)
{ /* the parent is the main beast */
authInfo->p.visibilityOverflow = zINVALID_ZID;
writeMainBeast = TRUE;
}
else
{ /* the parent is another overflow beast */
parentBeast = ZAS_LookupOverflowBeast(genMsg,
authBeast->AUTHvolume, overflowParentZid,
XLATCHED, zFTYPE_ZAS_VIS_OVERFLOW);
if (parentBeast == NULL)
{
goto errorTryNextTrustee;
}
parentBeast->p.nextOverflowZid = zINVALID_ZID;
COMN_MARK_BEAST_XLOCAL(&parentBeast->VISOroot, xaction);
COMN_ForceBeastWrite(genMsg, parentBeast, xaction);
COMN_UnlatchAndRelease(&parentBeast, XLATCHED);
}
}
else
{
COMN_MARK_BEAST_XLOCAL(&overflowBeast->VISOroot, xaction);
COMN_ForceBeastWrite(genMsg, overflowBeast, xaction);
COMN_UnlatchAndRelease(&overflowBeast, XLATCHED);
}
}
}
else
{
if (overflowBeast == NULL)
{ /* in the main beast */
COMN_MARK_BEAST_XLOCAL(&authBeast->AUTHroot, xaction);
COMN_ForceBeastWrite(genMsg, authBeast, xaction);
}
else
{ /* in an overflow beast */
COMN_MARK_BEAST_XLOCAL(&overflowBeast->VISOroot, xaction);
COMN_ForceBeastWrite(genMsg, overflowBeast, xaction);
COMN_UnlatchAndRelease(&overflowBeast, XLATCHED);
}
//#if NSS_DEBUG IS_ENABLED
//DBG_DebugPrintf(GREEN, MSGNot("\n(1)Exiting Remove Visibility -- Trustee: %x"), *trusteeID);
//DEBUG_Display_Visibility(authBeast);
//#endif
goto visibilityDoneForThisTrustee;
}
if (writeMainBeast)
{ /* if the main beast is dirty */
COMN_MARK_BEAST_XLOCAL(&authBeast->AUTHroot, xaction);
COMN_ForceBeastWrite(genMsg, authBeast, xaction);
writeMainBeast = FALSE;
}
//#if NSS_DEBUG IS_ENABLED
//DBG_DebugPrintf(GREEN, MSGNot("\n(2)Exiting Remove Visibility -- Trustee: %x"), *trusteeID);
//DEBUG_Display_Visibility(authBeast);
//#endif
if (authBeast->AUTHzid != zROOTDIR_ZID)
{
SETUP_FIX_VISIBILITY_PURGE_LOG(&purgeLogMsg, pLogLocPtr,
VIS_ACTION_REMOVE, authBeast->AUTHfirstParentZid, trusteeID);
if (authBeast->AUTHcomnVolOps.VOL_addPurgeLogEntry(
genMsg, authBeast->AUTHvolume,
PLOG_FIX_VISIBILITY, &purgeLogMsg, xaction) != zOK)
{
goto errorTryNextTrustee;
}
}
trusteeID++;
pLogLocPtr++;
i++;
COMN_EndXLocal(authBeast, &xaction);
continue;
errorTryNextTrustee:
errPrintf(WHERE, Module, 713,
MSG("Error removing visibility for a trustee.\n", 1194));
visibilityDoneForThisTrustee:
(*trusteeCount)--;
*trusteeID = trusteeIDList[*trusteeCount];
*pLogLocPtr = pLogLocPtrList[*trusteeCount];
COMN_EndXLocal(authBeast, &xaction);
continue;
}
xaction = COMN_BeginXLocal(authBeast);
VOL_insertEFLEntry(genMsg, &authBeast->AUTHroot,
EFL_FILE_STATE_MODIFY_METADATA, NULL, xaction);
COMN_EndXLocal(authBeast, &xaction);
if ((authBeast->AUTHzid == zROOTDIR_ZID) || (*trusteeCount == 0))
{
goto doneFixingVisibility;
}
parentZID = authBeast->AUTHfirstParentZid;
/* We do not want a yield between the UNX_LATCH of authBeast and
* X_LATCH request of the parent Beast below. Hence we look
* up the parent beast first in unlatched mode and then later
* request a latch on it
*
* This routine's calling function has to guarantee that when we
* return from here, the first thing we do is request a latch
* on the returned pBeast, without any yields in between
*/
pBeast = (AuthBeast_s *)BEASTHASH_LookupByZid(genMsg, volume,
parentZID, NOTLATCHED);
if (pBeast == NULL)
{ /* error */
SetErrno(genMsg, zERR_UNABLE_TO_OPEN_BEAST);
goto errorCleanup;
}
authInfo->flags &= ~ZAS_ALLOW_FORCED_WRITE;
UNX_LATCH(&authInfo->authLatch);
UNX_LATCH(&authBeast->AUTHbeastLatch);
return pBeast;
errorCleanup:
errPrintf(WHERE, Module, 714,
MSG("Error removing visibility for trustees just removed\n", 987));
doneFixingVisibility:
authInfo->flags &= ~ZAS_ALLOW_FORCED_WRITE;
UNX_LATCH(&authInfo->authLatch);
COMN_UnlatchAndRelease(&authBeast, XLATCHED);
return NULL;
}
/****************************************************************************
*
* These routines will switch from fsm to scheduling a work (after we get a
* latch on the parent beast we are fixing visibility on).
*
***************************************************************************/
void ZAS_FixVisibilityThread(FsmLite_s *fsm);
void ZAS_FixVisibilityGotParentLatch(FsmLite_s *fsm)
{
TotalVisibilityProcesses++;
WORK_Schedule(fsm, ZAS_FixVisibilityThread, 0);
return;
}
void ZAS_FixVisibilityThread(FsmLite_s *fsm)
{
GeneralMsg_s genMsg;
FixVisibPurgeLogFsm_s *workFsm = (FixVisibPurgeLogFsm_s *)fsm;
AuthBeast_s *authBeast;
ASSERT_MPKNSS_LOCK();
COMN_SETUP_GENERAL_MSG_NOSA(&genMsg);
zASSERT(workFsm->action == VIS_ACTION_REMOVE ||
workFsm->action == VIS_ACTION_ADD);
authBeast = workFsm->parentBeast;
switch (workFsm->action)
{
case VIS_ACTION_ADD:
workFsm->parentBeast = ZAS_InternalMakeItVisible(
&genMsg,
workFsm->parentBeast,
workFsm->volume,
workFsm->trusteeID,
&workFsm->trusteeCount,
workFsm->purgeLogLocations);
break;
case VIS_ACTION_REMOVE:
workFsm->parentBeast = ZAS_InternalRemoveVisibility(
&genMsg,
workFsm->parentBeast,
workFsm->volume,
workFsm->trusteeID,
&workFsm->trusteeCount,
workFsm->purgeLogLocations);
break;
}
TotalVisibilityProcesses--;
/* IMPORTANT NOTE: If the return values from ZAS_MakeItVisible &
* ZAS_InternalRemovingVisibility are non-NULL, the last thing they
* do is UNX_LATCH the previous parentBeast (we have it saved in the
* authBeast pointer.
*
* There should be no yield between the return from that call and
* queueing for a X_LATCH using the FSM_X_LATCH below. So do not put
* any code here.
*
* A NULL return from the above routines implies that visibility
* has been added/removed and all the beasts have been unlatched,
* and released. All we need to do is cleanup the workFsm
*/
if (workFsm->parentBeast != NULL)
{
FSM_X_LATCH(&workFsm->parentBeast->AUTHbeastLatch, &workFsm->fsm,
ZAS_FixVisibilityGotParentLatch);
COMN_Release(&authBeast);
}
else
{
--workFsm->volume->VOLv_keepActiveUseCount;
free(workFsm);
}
return;
}
/****************************************************************************
*
* This routine will set up fsm to add/remove visibility up the tree
*
***************************************************************************/
STATUS ZAS_FixVisibilityFsmStart(
GeneralMsg_s *genMsg,
Xaction_s *xaction,
AuthBeast_s *authBeast,
Zid_t parentZID,
UserID_t *trusteeID,
NINT trusteeCount,
BOOL checkForVisRebuild,
LONG action)
{
PurgeLogMsg_s purgeLogMsg;
FixVisibPurgeLogFsm_s *workFsm;
STATUS status = zOK;
AuthBeast_s *parentBeast;
FixVisibPLog_s *pLogLocations;
NINT i;
Volume_s *vol = authBeast->AUTHvolume;
ASSERT_MPKNSS_LOCK();
/*This routine assumes the beast is already open and the auth latch is set*/
ENTER(TAUTH, ZAS_FixVisibilityFsmStart);
ASSERT_XLATCH(&authBeast->AUTHauthInfo.zas->authLatch);
zASSERT(action == VIS_ACTION_ADD || action == VIS_ACTION_REMOVE);
/*
* If the visibility lists of the volume are being rebuilt then return
* unless we are already in the rebuild pass and the rebuild has passed
* the beast we are adding to.
*/
if (checkForVisRebuild && (vol->v_statusFlag & VOL_SF_CLEAN_VIS_SCHEDULED))
{
if (vol->v_statusFlag & VOL_SF_CLEAN_VIS_REBUILD)
{
if (authBeast->AUTHzid >= vol->VOLzidInProcess)
{
return zOK;
}
}
else
{
return zOK;
}
}
if (authBeast->AUTHzid == zROOTDIR_ZID)
{
RTN_STATUS(zOK);
}
if (trusteeCount == 0)
{
RTN_STATUS(zOK);
}
workFsm = zalloc(sizeof(FixVisibPurgeLogFsm_s) +
(trusteeCount * sizeof(UserID_t)) +
(trusteeCount * sizeof(FixVisibPLog_s)));
if (workFsm == NULL)
{
SetErrno(genMsg, zERR_NO_MEMORY);
RTN_STATUS(zFAILURE);
}
/* We lookup the beast not latched since it can yield, before we
* unlock the previous beast. We want the unlock and request for
* the latch on this beast to be simultaneous, without a yield
* in between.
*/
parentBeast = (AuthBeast_s *)BEASTHASH_LookupByZid(genMsg,
authBeast->AUTHvolume, parentZID, NOTLATCHED);
if (parentBeast == NULL)
{
ForceSetErrno(genMsg, zERR_UNABLE_TO_OPEN_BEAST);
free(workFsm);
RTN_STATUS(zFAILURE);
}
FSMLITE_INIT(&workFsm->fsm, MSGNot("FSM to fix visibility"), 0);
workFsm->parentBeast = parentBeast;
workFsm->trusteeID = (UserID_t *)((ADDR)workFsm +
sizeof(FixVisibPurgeLogFsm_s));
workFsm->trusteeCount = trusteeCount;
workFsm->volume = authBeast->AUTHvolume;
workFsm->action = action;
memcpy(workFsm->trusteeID, trusteeID, (trusteeCount * sizeof(UserID_t)));
workFsm->purgeLogLocations = (FixVisibPLog_s *)((ADDR)workFsm +
sizeof(FixVisibPurgeLogFsm_s) +
(trusteeCount * sizeof(UserID_t)));
++workFsm->volume->VOLv_keepActiveUseCount;
pLogLocations = workFsm->purgeLogLocations;
for (i = 0; i < trusteeCount; i++)
{
SETUP_FIX_VISIBILITY_PURGE_LOG(&purgeLogMsg,
pLogLocations, action, parentZID, trusteeID);
status = authBeast->AUTHcomnVolOps.VOL_addPurgeLogEntry(
genMsg, authBeast->AUTHvolume,
PLOG_FIX_VISIBILITY, &purgeLogMsg, xaction);
if (status == zOK)
{
trusteeID++;
pLogLocations++;
}
else
{
break;
}
}
if (status != zOK)
{
--workFsm->volume->VOLv_keepActiveUseCount;
free(workFsm);
RTN_STATUS(zFAILURE);
}
FSM_X_LATCH(&workFsm->parentBeast->AUTHbeastLatch, &workFsm->fsm,
ZAS_FixVisibilityGotParentLatch);
RTN_STATUS(zOK);
}
/****************************************************************************
*
* This routine will start a fsm to add visibility up the tree
*
***************************************************************************/
STATUS ZAS_MakeItVisible(
GeneralMsg_s *genMsg,
Xaction_s *xaction,
AuthBeast_s *authBeast,
Zid_t parentZID,
UserID_t *trusteeID,
NINT trusteeCount,
BOOL checkForVisRebuild)
{
return ZAS_FixVisibilityFsmStart(genMsg, xaction, authBeast, parentZID,
trusteeID, trusteeCount,
checkForVisRebuild, VIS_ACTION_ADD);
}
/****************************************************************************
*
* This routine will start a fsm to remove visibility up the tree
*
***************************************************************************/
STATUS ZAS_RemoveVisibility(
GeneralMsg_s *genMsg,
Xaction_s *xaction,
AuthBeast_s *authBeast,
Zid_t parentZID,
UserID_t *trusteeID,
NINT trusteeCount,
BOOL checkForVisRebuild)
{
return ZAS_FixVisibilityFsmStart(genMsg, xaction, authBeast, parentZID,
trusteeID, trusteeCount, checkForVisRebuild,
VIS_ACTION_REMOVE);
}
/***************************************************************************
*
* This routine is called from PlayPurgeLog to finish fixing up visibility
*
***************************************************************************/
STATUS ZAS_FixVisibility(
GeneralMsg_s *genMsg,
NINT action,
Volume_s *volume,
Zid_t parentZID,
UserID_t *trusteeID,
void *purgeLogLoc)
{
STATUS status = zOK;
UserID_t localTrusteeID = *trusteeID;
AuthBeast_s *authBeast;
AuthBeast_s *parentBeast;
NINT trusteeCount = 1;
parentBeast = (AuthBeast_s *)BEASTHASH_LookupByZid(genMsg, volume,
parentZID, NOTLATCHED);
if (parentBeast == NULL)
{
ForceSetErrno(genMsg, zERR_UNABLE_TO_OPEN_BEAST);
return zFAILURE;
}
TotalVisibilityProcesses++;
X_LATCH(&parentBeast->AUTHbeastLatch);
ClearErrno(genMsg);
for (;;)
{
authBeast = parentBeast;
switch (action)
{
case VIS_ACTION_ADD:
parentBeast = ZAS_InternalMakeItVisible(genMsg, parentBeast,
volume, &localTrusteeID, &trusteeCount, purgeLogLoc);
break;
case VIS_ACTION_REMOVE:
parentBeast = ZAS_InternalRemoveVisibility(genMsg, parentBeast,
volume, &localTrusteeID, &trusteeCount, purgeLogLoc);
break;
}
TotalVisibilityProcesses--;
if (parentBeast == NULL)
{
if (GetErrno(genMsg) != zOK)
{
status = zFAILURE;
}
break;
}
else
{
TotalVisibilityProcesses++;
X_LATCH(&parentBeast->AUTHbeastLatch);
COMN_Release(&authBeast);
}
}
return status;
}
/****************************************************************************
* This routine will check visibility rights for an object
****************************************************************************/
STATUS ZAS_CheckInheritedVisibility(
GeneralMsg_s *genMsg,
AuthBeast_s *authBeast,
NINT numIDs,
UserID_t *IDs)
{
Zid_t dummyZid;
NINT connectIndex;
NINT entryIndex;
VisEntry_s *entry;
ZASAuthorizeInfo_s *authInfo;
ZasVisOverflowBeast_s *beast;
ASSERT_MPKNSS_LOCK();
ENTER(TAUTH, ZAS_CheckInheritedVisibility);
authInfo = authBeast->AUTHauthInfo.zas;
S_LATCH(&authInfo->authLatch);
if ((authInfo->p.numVisibilityTrusteesAssigned > 0) ||
(authInfo->p.visibilityOverflow != zINVALID_ZID))
{ /* there are visibility entries */
for (connectIndex = 0; connectIndex < numIDs;
connectIndex++)
{ /* for each entry in the connection structure */
if (ZAS_FindVisibilityTrustee(genMsg, authBeast, NULL,
&IDs[connectIndex],
SLATCHED, &entry, &entryIndex, &beast, &dummyZid) != zOK)
{
goto error;
}
if (beast != NULL)
{
COMN_UnlatchAndRelease(&beast, SLATCHED);
}
if (entry != NULL)
{
UNS_LATCH(&authInfo->authLatch);
RTN_STATUS(zOK);
}
}
}
/* visibility not found */
#if NSS_DEBUG IS_ENABLED
DBG_DebugPrintf(LRED, MSGNot("Trustees in the connection structure:\n"));
for (connectIndex = 0; connectIndex < numIDs;
connectIndex++)
{
DBG_DebugPrintf(CYAN, MSGNot(" (%d) Trustee: %08x-%04x-%04x-%02x%02x-%02x%02x%02x%02x%02x%02x\n"),
connectIndex,
IDs[connectIndex].timeLow,
IDs[connectIndex].timeMid,
IDs[connectIndex].timeHighAndVersion,
IDs[connectIndex].clockSeqHighAndReserved,
IDs[connectIndex].clockSeqLow,
IDs[connectIndex].node[0],
IDs[connectIndex].node[1],
IDs[connectIndex].node[2],
IDs[connectIndex].node[3],
IDs[connectIndex].node[4],
IDs[connectIndex].node[5]);
}
DEBUG_Display_Visibility(authBeast);
DBG_DebugPrintf(LRED, "\n");
#endif
error:
UNS_LATCH(&authInfo->authLatch);
RTN_STATUS(zFAILURE);
}
EXPORT_SYMBOL(ZAS_CheckInheritedVisibility);
/***************************************************************************
*
* This routine adds all of the ACLs in a beast to the visibility.
*
***************************************************************************/
STATUS ZAS_AddBeastVisibility(
GeneralMsg_s *genMsg,
AuthBeast_s *authBeast,
Zid_t parentZid,
BOOL includeVisEntries,
VisRebuildStats_s *stats,
BOOL checkForVisRebuild)
{
ZASAuthorizeInfo_s *authInfo;
Xaction_s *xaction;
NINT originalCount;
ACLEntry_s *allACLs = NULL;
UserID_t *trusteeID = NULL;
VisEntry_s *allVis = NULL;
NINT i;
STATUS status = zOK;
ASSERT_MPKNSS_LOCK();
/*
* Fix up the visibility inheritance
*/
authInfo = authBeast->AUTHauthInfo.zas;
if (authInfo->p.numTrusteesAssigned == 0)
{
if (includeVisEntries)
{
if (authInfo->p.numVisibilityTrusteesAssigned == 0)
{
return zOK;
}
}
else
{
return zOK;
}
}
X_LATCH(&authInfo->authLatch);
if (authInfo->p.numTrusteesAssigned != 0)
{
NINT trusteeCount;
if (ZAS_CountACLs(genMsg, authBeast, &originalCount) != zOK)
{
status = zFAILURE;
goto exit;
}
zASSERT(originalCount > 0);
if ((allACLs = malloc(originalCount * sizeof(ACLEntry_s))) == NULL)
{
SetErrno(genMsg, zERR_NO_MEMORY);
status = zFAILURE;
goto exit;
}
if ((trusteeID = malloc(originalCount * sizeof(UserID_t))) == NULL)
{
SetErrno(genMsg, zERR_NO_MEMORY);
status = zFAILURE;
goto exit;
}
if (ZAS_GetAllACLs(genMsg, authBeast, allACLs, originalCount) != zOK)
{
status = zFAILURE;
goto exit;
}
/*
* We do not want to add visibility if the trustee has no rights, so
* remove any entries where there are no rights.
*/
trusteeCount = 0;
for (i = 0; i < originalCount; i++)
{
trusteeID[trusteeCount] = allACLs[i].trusteeID;
if (allACLs[i].rights)
{
trusteeCount++;
}
}
if (trusteeCount != 0)
{
if (stats)
{
stats->VisNumTrusteesProcessed += trusteeCount;
}
/*
* Update the visibility entries up the tree
*/
xaction = COMN_BeginXLocal(authBeast);
ZAS_MakeItVisible(genMsg, xaction, authBeast, parentZid, trusteeID,
trusteeCount, checkForVisRebuild);
COMN_EndXLocal(authBeast, &xaction);
}
free(trusteeID);
trusteeID = NULL;
free(allACLs);
allACLs = NULL;
}
/*
* Fix up the visibility inheritance for exisiting visibility entries
*/
if (includeVisEntries && authInfo->p.numVisibilityTrusteesAssigned != 0)
{
if (ZAS_CountVis(genMsg, authBeast, &originalCount) != zOK)
{
status = zFAILURE;
goto exit;
}
zASSERT(originalCount > 0);
if ((allVis = malloc(originalCount * sizeof(VisEntry_s))) == NULL)
{
SetErrno(genMsg, zERR_NO_MEMORY);
status = zFAILURE;
goto exit;
}
if ((trusteeID = malloc(originalCount * sizeof(UserID_t))) == NULL)
{
SetErrno(genMsg, zERR_NO_MEMORY);
status = zFAILURE;
goto exit;
}
if (ZAS_GetAllVis(genMsg, authBeast, allVis, originalCount) != zOK)
{
status = zFAILURE;
goto exit;
}
/*
* Move an entry into the trustee array for each visibility entry
* to be added.
*/
for (i = 0; i < originalCount; i++)
{
trusteeID[i] = allVis[i].trusteeID;
}
/*
* Update the visibility entries up the tree
*/
xaction = COMN_BeginXLocal(authBeast);
ZAS_MakeItVisible(genMsg, xaction, authBeast, parentZid, trusteeID,
originalCount, checkForVisRebuild);
COMN_EndXLocal(authBeast, &xaction);
}
exit:
free(trusteeID);
free(allACLs);
UNX_LATCH(&authInfo->authLatch);
return status;
}
/***************************************************************************
*
* This routine is called when a name is added to the name tree. It adds
* the trustees in the ACL to the visiblity list.
*
***************************************************************************/
STATUS VAUTH_AddAuthInfo(
GeneralMsg_s *genMsg,
AuthBeast_s *authBeast,
Zid_t parentZid,
Latch_s *parentLatch)
{
return ZAS_AddBeastVisibility(genMsg, authBeast, parentZid, TRUE, NULL, TRUE);
}
/***************************************************************************
*
* This routine is called when a name is deleted from the name tree
*
***************************************************************************/
STATUS VAUTH_RemoveAuthInfo(
GeneralMsg_s *genMsg,
AuthBeast_s *authBeast,
Zid_t parentZid,
Xaction_s *xaction)
{
ZASAuthorizeInfo_s *authInfo;
NINT originalCount;
ACLEntry_s *allACLs = NULL;
VisEntry_s *allVis = NULL;
UserID_t *trusteeID = NULL;
NINT i;
STATUS status = zOK;
ASSERT_MPKNSS_LOCK();
ENTER(TAUTH, VAUTH_RemoveAuthInfo);
/*
* Fix up the visibility inheritance for ACLs
*/
authInfo = authBeast->AUTHauthInfo.zas;
if (authInfo->p.numTrusteesAssigned == 0 &&
authInfo->p.numVisibilityTrusteesAssigned == 0)
{ /* if there are no trustees assigned then just return */
RTN_STATUS(zOK);
}
X_LATCH(&authInfo->authLatch);
if (authInfo->p.numTrusteesAssigned != 0)
{
NINT trusteeCount;
if (ZAS_CountACLs(genMsg, authBeast, &originalCount) != zOK)
{
status = zFAILURE;
goto exit;
}
zASSERT(originalCount > 0);
if ((allACLs = malloc(originalCount * sizeof(ACLEntry_s))) == NULL)
{
SetErrno(genMsg, zERR_NO_MEMORY);
status = zFAILURE;
goto exit;
}
if ((trusteeID = malloc(originalCount * sizeof(UserID_t))) == NULL)
{
SetErrno(genMsg, zERR_NO_MEMORY);
status = zFAILURE;
goto exit;
}
if (ZAS_GetAllACLs(genMsg, authBeast, allACLs, originalCount) != zOK)
{
status = zFAILURE;
goto exit;
}
/*
* We do not want to remove visibility if the trustee has no rights, so
* remove any entries where there are no rights.
*/
trusteeCount = 0;
for (i = 0; i < originalCount; i++)
{
trusteeID[trusteeCount] = allACLs[i].trusteeID;
if (allACLs[i].rights)
{
trusteeCount++;
}
}
if (trusteeCount != 0)
{
/*
* Remove the visibility for the trustee from the entries up the tree
*/
ZAS_RemoveVisibility(genMsg, xaction, authBeast, parentZid, trusteeID,
trusteeCount, TRUE);
}
free(trusteeID);
trusteeID = NULL;
free(allACLs);
allACLs = NULL;
}
/*
* Fix up the visibility inheritance for exisiting visibility entries
*/
if (authInfo->p.numVisibilityTrusteesAssigned != 0)
{
if (ZAS_CountVis(genMsg, authBeast, &originalCount) != zOK)
{
status = zFAILURE;
goto exit;
}
zASSERT(originalCount > 0);
if ((allVis = malloc(originalCount * sizeof(VisEntry_s))) == NULL)
{
SetErrno(genMsg, zERR_NO_MEMORY);
status = zFAILURE;
goto exit;
}
if ((trusteeID = malloc(originalCount * sizeof(UserID_t))) == NULL)
{
SetErrno(genMsg, zERR_NO_MEMORY);
status = zFAILURE;
goto exit;
}
if (ZAS_GetAllVis(genMsg, authBeast, allVis, originalCount) != zOK)
{
status = zFAILURE;
goto exit;
}
/*
* Move an entry into the trustee array for each visibility entry
* to be added.
*/
for (i = 0; i < originalCount; i++)
{
trusteeID[i] = allVis[i].trusteeID;
}
/*
* Remove the visibility for the trustee from the entries up the tree
*/
ZAS_RemoveVisibility(genMsg, xaction, authBeast, parentZid, trusteeID,
originalCount, TRUE);
}
exit:
free(trusteeID);
free(allACLs);
free(allVis);
UNX_LATCH(&authInfo->authLatch);
RTN_STATUS(status);
}
/***************************************************************************
*
* This routine is called when a file is actually deleted. It cleans up the
* associated overflow beasts.
*
***************************************************************************/
STATUS VAUTH_DeleteAuthInfo(
GeneralMsg_s *genMsg,
AuthBeast_s *authBeast,
Zid_t parentZid)
{
ZASAuthorizeInfo_s *authInfo;
Xaction_s *xaction;
ZasAclOverflowBeast_s *aclOverflowBeast;
ZasVisOverflowBeast_s *visOverflowBeast;
Zid_t overflowZid;
STATUS status;
ASSERT_MPKNSS_LOCK();
authInfo = authBeast->AUTHauthInfo.zas;
X_LATCH(&authInfo->authLatch);
/* Remove the ACL overflow beasts */
xaction = COMN_BeginXLocal(authBeast);
/* Remove all ACL overflow beasts */
overflowZid = authInfo->p.trusteeOverflow;
while (overflowZid != zINVALID_ZID)
{ /* find an overflow beast with an open entry */
aclOverflowBeast = ZAS_LookupOverflowBeast(genMsg, authBeast->AUTHvolume,
overflowZid, XLATCHED, zFTYPE_ZAS_ACL_OVERFLOW);
if (aclOverflowBeast == NULL)
{ /* error */
status = zFAILURE;
goto exit;
}
overflowZid = aclOverflowBeast->p.nextOverflowZid;
BST_delete(genMsg, NULL, aclOverflowBeast, NULL, NULL,
xaction, FALSE, TRUE);
COMN_UnlatchAndRelease(&aclOverflowBeast, XLATCHED);
}
status = zOK;
/* Remove all visibility overflow beasts */
overflowZid = authInfo->p.visibilityOverflow;
while (overflowZid != zINVALID_ZID)
{ /* find an overflow beast with an open entry */
visOverflowBeast = ZAS_LookupOverflowBeast(genMsg, authBeast->AUTHvolume,
overflowZid, XLATCHED, zFTYPE_ZAS_VIS_OVERFLOW);
if (visOverflowBeast == NULL)
{ /* error */
status = zFAILURE;
goto exit;
}
overflowZid = visOverflowBeast->p.nextOverflowZid;
BST_delete(genMsg, NULL, visOverflowBeast, NULL, NULL,
xaction, FALSE, TRUE);
COMN_UnlatchAndRelease(&visOverflowBeast, XLATCHED);
}
status = zOK;
exit:
COMN_EndXLocal(authBeast, &xaction);
UNX_LATCH(&authInfo->authLatch);
return status;
}
/***************************************************************************
*
* This routine is called to determine if there is auth info that needs
* to be cleaned up. If so then it returns TRUE.
*
***************************************************************************/
BOOL VAUTH_IsAuthInfo(
GeneralMsg_s *genMsg,
AuthBeast_s *authBeast)
{
ZASAuthorizeInfo_s *authInfo;
ASSERT_MPKNSS_LOCK();
authInfo = authBeast->AUTHauthInfo.zas;
if (authInfo->p.numTrusteesAssigned != 0)
{
return TRUE;
}
if (authInfo->p.trusteeOverflow != zINVALID_ZID)
{
return TRUE;
}
return FALSE;
}
/****************************************************************************
* This routine is used to initialize the authorization info for a newly
* created volume. It must only change items in the volume's rootdir.
* The caller will have the rootdir xlatched and will ensure that the
* rootdir gets written and the latch released on successful return. On
* error return the volume will not get created.
*****************************************************************************/
STATUS VAUTH_InitVolumeAuthInfo(
GeneralMsg_s *genMsg,
Volume_s *volBeast)
{
AuthBeast_s *rootdir = (AuthBeast_s *)volBeast->rootdir;
ASSERT_MPKNSS_LOCK();
ASSERT_XLATCH(&rootdir->AUTHbeastLatch);
/* allow no inheritance on rootdir */
rootdir->AUTHauthInfo.zas->p.inheritedRightsMask = 0;
return(zOK);
}
typedef struct SaveTrusteeEntry_s
{
NINT trusteeID;
NINT rights;
NINT attributes;
} SaveTrusteeEntry_s;
/****************************************************************************
*
* This routine removes a list of trustees from all objects in a given
* volume. Currently it is calling a routine that is also called from
* the authorization space for some symantic agent requests. The authorization
* space routine could have been placed directly in the ops tables, but since
* this is an infrequently used call I gave it its own routine to avoid
* confusion.
*
****************************************************************************/
STATUS VAUTH_RemoveIDsFromAVolume(
GeneralMsg_s *genMsg,
NamingMsg_s *nameMsg,
UserID_t *IDlist,
NINT IDcount)
{
ASSERT_MPKNSS_LOCK();
return VAUTH_PurgeACLEntriesFromTree(genMsg, nameMsg, IDlist, IDcount);
}
/****************************************************************************
*
* This function repairs a beast with a bad overflow zid
*
****************************************************************************/
void VAUTH_FixOverflowLink(
GeneralMsg_s *genMsg,
Volume_s *volume,
AuthBeast_s *beast,
Zid_t overflowZid)
{
ZasAclOverflowBeast_s *overflowBeast;
NINT unicodeLen;
unicode_t *name;
if (overflowZid == zINVALID_ZID)
{ /* The bad zid is in the file beast */
beast->AUTHauthInfo.zas->p.trusteeOverflow = zINVALID_ZID;
COMN_MARK_BEAST_DIRTY(&beast->AUTHroot);
}
else
{ /* The bad zid is in an overflow beast */
overflowBeast = ZAS_LookupOverflowBeast(genMsg, volume, overflowZid,
XLATCHED, zFTYPE_ZAS_ACL_OVERFLOW);
if (overflowBeast == NULL)
{
return;
}
overflowBeast->p.nextOverflowZid = zINVALID_ZID;
COMN_MARK_BEAST_DIRTY(&overflowBeast->ACLOroot);
COMN_UnlatchAndRelease(&overflowBeast, XLATCHED);
}
if (COMN_IsDerivedFrom(beast, zFTYPE_FILE))
{
name = malloc((zMAX_COMPONENT_NAME + 1) * sizeof(unicode_t));
if (name)
{
COMN_GetNameFromBeast(genMsg, (File_s *)beast, /* cnt zFNU_FIRST_PARENT,*/
zNSPACE_LONG, zMAX_COMPONENT_NAME, name, &unicodeLen);
name[unicodeLen] = L'\0';
aprintf(LRED, "Fixed bad authorization overflow link on file %U\n",
name);
free(name);
}
}
else
{
aprintf(LRED, "Fixed bad authorization overflow link. Zid=%Lu",
beast->AUTHzid);
}
}
/****************************************************************************
*
* This function adds the NDS object GUIDs to the User store for all
* structures in the ZAS auth model.
*
****************************************************************************/
STATUS VAUTH_CheckUserIDs(
GeneralMsg_s *genMsg,
Volume_s *volume,
AuthBeast_s *beast)
{
ZASAuthorizeInfo_s *authInfo;
NINT entry;
ZasAclOverflowBeast_s *overflowBeast;
Zid_t overflowZid;
BOOL isOK;
NINT numBadIDs;
Zid_t previousZid;
typedef struct Stack_s {
UserID_t badIDs[MAX_ACL_OVERFLOW_ENTRIES];
} Stack_s;
STACK_ALLOC();
authInfo = beast->AUTHauthInfo.zas;
X_LATCH(&authInfo->authLatch);
/* Check the trustees in the beast and the ACL overflow beasts */
for (entry=0; entry < authInfo->p.numTrusteesAssigned; entry++)
{
UserID_t userID = authInfo->p.ACL[entry].trusteeID;
if (CHK_VerifyID(genMsg, volume, &userID, &isOK) != zOK)
{
continue;
}
if (!isOK)
{
ZAS_RemoveLatchedACLEntry(genMsg, beast, &userID, TRUE, NULL);
}
}
/* check the overflow beasts for the entry */
overflowZid = authInfo->p.trusteeOverflow;
previousZid = zINVALID_ZID;
while (overflowZid != zINVALID_ZID)
{ /* find an overflow beast with an open entry */
overflowBeast = ZAS_LookupOverflowBeast(genMsg, volume, overflowZid,
SLATCHED, zFTYPE_ZAS_ACL_OVERFLOW);
if (overflowBeast == NULL)
{ /* error */
zASSERT("Error getting ACL overflow beast" == NULL);
VAUTH_FixOverflowLink(genMsg, volume, beast, previousZid);
break;
}
#if (CURRENT_BEAST_VERSION != BEAST_VERSION_3)
#error "Check to see if the beastVersion code below is still needed."
#endif
/* BEGINNING OF BEAST VERSION ONE CONVERSION CODE */
if (ZAS_ConvertACLFromVersionOne(genMsg, overflowBeast) != zOK)
{
COMN_UnlatchAndRelease(&overflowBeast, SLATCHED);
STACK_FREE();
return(zFAILURE);
}
/* END OF BEAST VERSION ONE CONVERSION CODE */
numBadIDs = 0;
for (entry = 0; entry < overflowBeast->p.numEntries; entry++)
{
if (CHK_VerifyID(genMsg, volume, &overflowBeast->acl[entry].trusteeID,
&isOK) != zOK)
{
continue;
}
if (!isOK)
{
aStack->badIDs[numBadIDs++] = overflowBeast->acl[entry].trusteeID;
}
}
UNS_LATCH(&overflowBeast->ACLObeastLatch);
/*
* We save up the bad IDs and remove them after the latch has been
* released so that we do not deadlock.
*/
while (numBadIDs > 0)
{
// DBG_DebugPrintf(LRED, "VAUTH_CheckUserIDs: removing user 0x%x\n", aStack->badIDs[numBadIDs - 1].timeLow);
ZAS_RemoveLatchedACLEntry(genMsg, beast,
&aStack->badIDs[--numBadIDs], TRUE, NULL);
}
previousZid = overflowZid;
overflowZid = overflowBeast->p.nextOverflowZid;
COMN_Release(&overflowBeast);
}
UNX_LATCH(&authInfo->authLatch);
STACK_FREE();
return zOK;
}
/****************************************************************************
*
* This function adds the NDS object GUIDs to the User store for all
* structures in the ZAS auth model.
*
****************************************************************************/
STATUS VAUTH_AddObjectNames(
GeneralMsg_s *genMsg,
Volume_s *volume,
AuthBeast_s *beast)
{
ZASAuthorizeInfo_s *authInfo;
NINT entry;
/* Add the trustees and visibility entries */
authInfo = beast->AUTHauthInfo.zas;
for (entry=0; entry < authInfo->p.numTrusteesAssigned; entry++)
{
OID_AddEntryIfNotThere(genMsg, volume,
&authInfo->p.ACL[entry].trusteeID);
}
for (entry=0; entry < authInfo->p.numVisibilityTrusteesAssigned;
entry++)
{
OID_AddEntryIfNotThere(genMsg, volume,
&authInfo->p.visibilityList[entry].trusteeID);
}
return zOK;
}
/***************************************************************************
*
* This routine is called when the information for the authorization system
* (i.e. caching) may need to be invalidated.
*
***************************************************************************/
STATUS VAUTH_InvalidateAuthInfo(
GeneralMsg_s *genMsg)
{
return ZAS_InvalidateEntireEACLCache(genMsg, TRUE);
}
/****************************************************************************
* This routine will count ACL entries for a file.
****************************************************************************/
STATUS ZAS_CountACLs(
GeneralMsg_s *genMsg,
AuthBeast_s *authBeast,
NINT *count)
{
ZASAuthorizeInfo_s *authInfo;
ZasAclOverflowBeast_s *overflowBeast;
Zid_t overflowZid;
ASSERT_MPKNSS_LOCK();
ENTER(TAUTH, ZAS_CountACLs);
authInfo = authBeast->AUTHauthInfo.zas;
ASSERT_LATCH(&authInfo->authLatch);
*count = authInfo->p.numTrusteesAssigned;
/* check the overflow beasts for the entry */
overflowZid = authInfo->p.trusteeOverflow;
while (overflowZid != zINVALID_ZID)
{ /* get the next overflow beast */
overflowBeast = ZAS_LookupOverflowBeast(genMsg, authBeast->AUTHvolume,
overflowZid, SLATCHED, zFTYPE_ZAS_ACL_OVERFLOW);
if (overflowBeast == NULL)
{ /* error */
RTN_STATUS(zFAILURE);
}
#if (CURRENT_BEAST_VERSION != BEAST_VERSION_3)
#error "Check to see if the beastVersion code below is still needed."
#endif
/* BEGINNING OF BEAST VERSION ONE CONVERSION CODE */
if (ZAS_ConvertACLFromVersionOne(genMsg, overflowBeast) != zOK)
{
COMN_UnlatchAndRelease(&overflowBeast, SLATCHED);
RTN_STATUS(zFAILURE);
}
/* END OF BEAST VERSION ONE CONVERSION CODE */
*count += overflowBeast->p.numEntries;
overflowZid = overflowBeast->p.nextOverflowZid;
COMN_UnlatchAndRelease(&overflowBeast, SLATCHED);
}
/* entry not found */
RTN_STATUS(zOK);
}
/****************************************************************************
* This routine will count visibility entries for a file.
****************************************************************************/
STATUS ZAS_CountVis(
GeneralMsg_s *genMsg,
AuthBeast_s *authBeast,
NINT *count)
{
ZASAuthorizeInfo_s *authInfo;
ZasVisOverflowBeast_s *overflowBeast;
Zid_t overflowZid;
ASSERT_MPKNSS_LOCK();
authInfo = authBeast->AUTHauthInfo.zas;
ASSERT_LATCH(&authInfo->authLatch);
*count = authInfo->p.numVisibilityTrusteesAssigned;
/* check the overflow beasts for the entry */
overflowZid = authInfo->p.visibilityOverflow;
while (overflowZid != zINVALID_ZID)
{ /* get the next overflow beast */
overflowBeast = ZAS_LookupOverflowBeast(genMsg, authBeast->AUTHvolume,
overflowZid, SLATCHED, zFTYPE_ZAS_VIS_OVERFLOW);
if (overflowBeast == NULL)
{ /* error */
return zFAILURE;
}
#if (CURRENT_BEAST_VERSION != BEAST_VERSION_3)
#error "Check to see if the beastVersion code below is still needed."
#endif
/* BEGINNING OF BEAST VERSION ONE CONVERSION CODE */
if (ZAS_ConvertVisFromVersionOne(genMsg, NULL, authBeast) != zOK)
{
COMN_UnlatchAndRelease(&overflowBeast, SLATCHED);
return zFAILURE;
}
/* END OF BEAST VERSION ONE CONVERSION CODE */
*count += overflowBeast->p.numEntries;
overflowZid = overflowBeast->p.nextOverflowZid;
COMN_UnlatchAndRelease(&overflowBeast, SLATCHED);
}
/* entry not found */
return zOK;
}
/****************************************************************************
* This routine will get an ACL entry for a file. If the sequence number is
* -1 or 0 then it gets the first entry, otherwise it gets the next one in
* the sequence. A returned sequence number of -1 means there are no more
* entries
****************************************************************************/
STATUS ZAS_GetAnACL(
GeneralMsg_s *genMsg,
AuthBeast_s *authBeast,
NINT *sequence,
UserID_t *trusteeID,
NINT *rights,
NINT *attributes)
{
ZASAuthorizeInfo_s *authInfo;
ZasAclOverflowBeast_s *overflowBeast;
Zid_t overflowZid;
NINT entry;
ASSERT_MPKNSS_LOCK();
ENTER(TAUTH, ZAS_GetAnACL);
if (*sequence == -1)
{ /* get the first entry */
*sequence = 0;
}
authInfo = authBeast->AUTHauthInfo.zas;
//FixFixFix: Need to think about this one:ASSERT_LATCH(&authInfo->authLatch);
entry = *sequence;
(*sequence)++;
/* check the main beast for the entry */
if (entry < authInfo->p.numTrusteesAssigned)
{ /* if the entry is in the main beast */
*trusteeID = authInfo->p.ACL[entry].trusteeID;
*rights = authInfo->p.ACL[entry].rights;
*attributes = authInfo->p.ACL[entry].attributes;
RTN_STATUS(zOK);
}
/* check the overflow beasts for the entry */
overflowZid = authInfo->p.trusteeOverflow;
entry -= authInfo->p.numTrusteesAssigned;
while (overflowZid != zINVALID_ZID)
{ /* find an overflow beast with an open entry */
overflowBeast = ZAS_LookupOverflowBeast(genMsg, authBeast->AUTHvolume,
overflowZid, SLATCHED, zFTYPE_ZAS_ACL_OVERFLOW);
if (overflowBeast == NULL)
{ /* error */
RTN_STATUS(zFAILURE);
}
#if (CURRENT_BEAST_VERSION != BEAST_VERSION_3)
#error "Check to see if the beastVersion code below is still needed."
#endif
/* BEGINNING OF BEAST VERSION ONE CONVERSION CODE */
if (ZAS_ConvertACLFromVersionOne(genMsg, overflowBeast) != zOK)
{
COMN_UnlatchAndRelease(&overflowBeast, SLATCHED);
RTN_STATUS(zFAILURE);
}
/* END OF BEAST VERSION ONE CONVERSION CODE */
if (entry < overflowBeast->p.numEntries)
{
*trusteeID = overflowBeast->acl[entry].trusteeID;
*rights = overflowBeast->acl[entry].rights;
*attributes = overflowBeast->acl[entry].attributes;
COMN_UnlatchAndRelease(&overflowBeast, SLATCHED);
RTN_STATUS(zOK);
}
overflowZid = overflowBeast->p.nextOverflowZid;
entry -= overflowBeast->p.numEntries;
COMN_UnlatchAndRelease(&overflowBeast, SLATCHED);
}
/* entry not found */
*sequence = -1;
RTN_STATUS(zOK);
}
/****************************************************************************
* This routine will get all ACL entries for a file.
* trusteeID is a pointer to an array to fill in the trustee IDs.
* count is the size of the array.
****************************************************************************/
STATUS ZAS_GetAllACLs(
GeneralMsg_s *genMsg,
AuthBeast_s *authBeast,
ACLEntry_s *acl,
NINT count)
{
ZASAuthorizeInfo_s *authInfo;
ZasAclOverflowBeast_s *overflowBeast;
Zid_t overflowZid;
NINT entry;
NINT i;
ASSERT_MPKNSS_LOCK();
ENTER(TAUTH, ZAS_GetAllACLs);
authInfo = authBeast->AUTHauthInfo.zas;
ASSERT_LATCH(&authInfo->authLatch);
entry = 0;
/* check the main beast for the entry */
for (i = 0; ((i < authInfo->p.numTrusteesAssigned) && (entry < count));
entry++, i++)
{
acl[entry] = authInfo->p.ACL[i];
}
if (entry == count)
{
RTN_STATUS(zOK);
}
/* check the overflow beasts for the entry */
overflowZid = authInfo->p.trusteeOverflow;
while (overflowZid != zINVALID_ZID)
{ /* get the next overflow entry */
overflowBeast = ZAS_LookupOverflowBeast(genMsg, authBeast->AUTHvolume,
overflowZid, SLATCHED, zFTYPE_ZAS_ACL_OVERFLOW);
if (overflowBeast == NULL)
{ /* error */
RTN_STATUS(zFAILURE);
}
#if (CURRENT_BEAST_VERSION != BEAST_VERSION_3)
#error "Check to see if the beastVersion code below is still needed."
#endif
/* BEGINNING OF BEAST VERSION ONE CONVERSION CODE */
if (ZAS_ConvertACLFromVersionOne(genMsg, overflowBeast) != zOK)
{
COMN_UnlatchAndRelease(&overflowBeast, SLATCHED);
RTN_STATUS(zFAILURE);
}
/* END OF BEAST VERSION ONE CONVERSION CODE */
for (i = 0; ((i < overflowBeast->p.numEntries) && (entry < count));
entry++, i++)
{
acl[entry] = overflowBeast->acl[i];
}
overflowZid = overflowBeast->p.nextOverflowZid;
COMN_UnlatchAndRelease(&overflowBeast, SLATCHED);
if (entry == count)
{
RTN_STATUS(zOK);
}
}
zASSERT(entry == count);
RTN_STATUS(zOK);
}
/****************************************************************************
* This routine will get all visibility entries for a file.
* trusteeID is a pointer to an array to fill in the trustee IDs.
* count is the size of the array.
****************************************************************************/
STATUS ZAS_GetAllVis(
GeneralMsg_s *genMsg,
AuthBeast_s *authBeast,
VisEntry_s *vis,
NINT count)
{
ZASAuthorizeInfo_s *authInfo;
ZasVisOverflowBeast_s *overflowBeast;
Zid_t overflowZid;
NINT entry = 0;
NINT i;
ASSERT_MPKNSS_LOCK();
authInfo = authBeast->AUTHauthInfo.zas;
ASSERT_LATCH(&authInfo->authLatch);
/* check the main beast for the entry */
for (i = 0; i < authInfo->p.numVisibilityTrusteesAssigned; i++)
{
zASSERT(entry < count);
if (entry < count)
{
vis[entry++] = authInfo->p.visibilityList[i];
}
}
/* check the overflow beasts for the entry */
overflowZid = authInfo->p.visibilityOverflow;
while (overflowZid != zINVALID_ZID)
{ /* get the next overflow beast */
overflowBeast = ZAS_LookupOverflowBeast(genMsg, authBeast->AUTHvolume,
overflowZid, SLATCHED, zFTYPE_ZAS_VIS_OVERFLOW);
if (overflowBeast == NULL)
{ /* error */
return zFAILURE;
}
#if (CURRENT_BEAST_VERSION != BEAST_VERSION_3)
#error "Check to see if the beastVersion code below is still needed."
#endif
/* BEGINNING OF BEAST VERSION ONE CONVERSION CODE */
if (ZAS_ConvertVisFromVersionOne(genMsg, NULL, authBeast) != zOK)
{
COMN_UnlatchAndRelease(&overflowBeast, SLATCHED);
return zFAILURE;
}
/* END OF BEAST VERSION ONE CONVERSION CODE */
for (i = 0; i < overflowBeast->p.numEntries; i++)
{
zASSERT(entry < count);
if (entry < count)
{
vis[entry++] = overflowBeast->vis[i];
}
}
overflowZid = overflowBeast->p.nextOverflowZid;
COMN_UnlatchAndRelease(&overflowBeast, SLATCHED);
}
zASSERT(entry == count);
return zOK;
}
/****************************************************************************
* This routine will find a trustee and return a pointer to the trustee
* info and if it is in the overflow then a pointer the overflow beast is
* returned.
* If it is in the overflow then the overflow beast is returned open and
* latched.
****************************************************************************/
ACLEntry_s *ZAS_FindTrustee(
GeneralMsg_s *genMsg,
AuthBeast_s *authBeast,
UserID_t *trusteeID,
ZasAclOverflowBeast_s **returnBeast)
{
ZASAuthorizeInfo_s *authInfo;
ZasAclOverflowBeast_s *overflowBeast;
Zid_t overflowZid;
NINT entry;
ASSERT_MPKNSS_LOCK();
ENTER(TAUTH, ZAS_FindTrustee);
authInfo = authBeast->AUTHauthInfo.zas;
ASSERT_LATCH(&authInfo->authLatch);
*returnBeast = NULL;
/* search the main beast for the trustee */
for (entry=0; entry < authInfo->p.numTrusteesAssigned; entry++)
{
if (LB_GUIDCompare(&authInfo->p.ACL[entry].trusteeID, trusteeID) == 0)
{
RTN_PTR(&authInfo->p.ACL[entry]);
}
}
/* search the overflow beasts for the trustee */
overflowZid = authInfo->p.trusteeOverflow;
while (overflowZid != zINVALID_ZID)
{
overflowBeast = ZAS_LookupOverflowBeast(genMsg, authBeast->AUTHvolume,
overflowZid, XLATCHED, zFTYPE_ZAS_ACL_OVERFLOW);
if (overflowBeast == NULL)
{ /* error */
RTN_PTR(NULL);
}
#if (CURRENT_BEAST_VERSION != BEAST_VERSION_3)
#error "Check to see if the beastVersion code below is still needed."
#endif
/* BEGINNING OF BEAST VERSION ONE CONVERSION CODE */
if (ZAS_ConvertACLFromVersionOne(genMsg, overflowBeast) != zOK)
{
COMN_UnlatchAndRelease(&overflowBeast, XLATCHED);
RTN_PTR(NULL);
}
/* END OF BEAST VERSION ONE CONVERSION CODE */
for (entry=0; entry < overflowBeast->p.numEntries; entry++)
{
if (LB_GUIDCompare(&overflowBeast->acl[entry].trusteeID, trusteeID) == 0)
{
*returnBeast = overflowBeast;
RTN_PTR(&overflowBeast->acl[entry]);
}
}
overflowZid = overflowBeast->p.nextOverflowZid;
COMN_UnlatchAndRelease(&overflowBeast, XLATCHED);
}
RTN_PTR(NULL);
}
/****************************************************************************
* This routine will add room for a trustee and return a pointer to the trustee
* info and a pointer to the overflow beast if it is added to the overflow.
* If it is in the overflow then the overflow beast is returned open and
* latched.
****************************************************************************/
ACLEntry_s *ZAS_AddTrustee(
GeneralMsg_s *genMsg,
AuthBeast_s *authBeast,
Xaction_s *xaction,
BOOL *writeMainBeast,
ZasAclOverflowBeast_s **returnBeast)
{
ACLEntry_s *aclEntry;
ZASAuthorizeInfo_s *authInfo;
Zid_t overflowZid;
ZasAclOverflowBeast_s *overflowBeast;
ZasAclOverflowBeast_s *oldOverflowBeast = NULL;
STATUS status;
ASSERT_MPKNSS_LOCK();
ENTER(TAUTH, ZAS_AddTrustee);
*writeMainBeast = FALSE;
authInfo = authBeast->AUTHauthInfo.zas;
ASSERT_LATCH(&authInfo->authLatch);
if (authInfo->p.numTrusteesAssigned < MAX_TRUSTEES_IN_BEAST)
{ /* if there is still space in the main beast */
aclEntry = &authInfo->p.ACL[authInfo->p.numTrusteesAssigned++];
*returnBeast = NULL;
*writeMainBeast = TRUE;
}
else
{ /* move to the overflow beasts */
overflowZid = authInfo->p.trusteeOverflow;
if (authInfo->p.trusteeOverflow != zINVALID_ZID)
{
for (;;)
{ /* find an overflow beast with an open entry */
overflowBeast = ZAS_LookupOverflowBeast(genMsg, authBeast->AUTHvolume,
overflowZid, XLATCHED, zFTYPE_ZAS_ACL_OVERFLOW);
if (overflowBeast == NULL)
{ /* error */
RTN_PTR(NULL);
}
#if (CURRENT_BEAST_VERSION != BEAST_VERSION_3)
#error "Check to see if the beastVersion code below is still needed."
#endif
/* BEGINNING OF BEAST VERSION ONE CONVERSION CODE */
if (ZAS_ConvertACLFromVersionOne(genMsg, overflowBeast) != zOK)
{
COMN_UnlatchAndRelease(&overflowBeast, XLATCHED);
RTN_PTR(NULL);
}
/* END OF BEAST VERSION ONE CONVERSION CODE */
if (overflowBeast->p.numEntries < MAX_ACL_OVERFLOW_ENTRIES)
{ /* if there is room in this node */
if (overflowBeast->p.numEntries >= overflowBeast->numAlloced)
{ /* if we need to make the memory structure bigger */
ACLEntry_s *acl;
overflowBeast->numAlloced += OVERFLOW_ALLOC_UNIT;
acl = realloc(overflowBeast->acl,
overflowBeast->numAlloced * sizeof (ACLEntry_s));
if (acl == NULL)
{
overflowBeast->numAlloced -= OVERFLOW_ALLOC_UNIT;
SetErrno(genMsg, zERR_NO_MEMORY);
COMN_UnlatchAndRelease(&overflowBeast, XLATCHED);
RTN_PTR(NULL);
}
overflowBeast->acl = acl;
}
aclEntry = &overflowBeast->acl[overflowBeast->p.numEntries++];
*returnBeast = overflowBeast;
RTN_PTR(aclEntry);
}
overflowZid = overflowBeast->p.nextOverflowZid;
oldOverflowBeast = overflowBeast;
if (overflowZid != zINVALID_ZID)
{
COMN_UnlatchAndRelease(&overflowBeast, XLATCHED);
oldOverflowBeast = NULL;
}
else
{ /* no open entries in the overflow beasts */
break;
}
}
}
/*
* Add a new overflow beast
*/
overflowBeast = (ZasAclOverflowBeast_s *)BST_create(genMsg,
zFTYPE_ZAS_ACL_OVERFLOW, authBeast->AUTHvolume, xaction);
if (overflowBeast == NULL)
{
if (oldOverflowBeast != NULL)
{
COMN_UnlatchAndRelease(&oldOverflowBeast, XLATCHED);
}
RTN_PTR(NULL);
}
/* link the new beast to the ones already there */
if (oldOverflowBeast == NULL)
{ /* link to main beast */
authInfo->p.trusteeOverflow = overflowBeast->ACLOzid;
*writeMainBeast = TRUE;
}
else
{ /* link to another overflow beast */
oldOverflowBeast->p.nextOverflowZid = overflowBeast->ACLOzid;
COMN_MARK_BEAST_XLOCAL(&oldOverflowBeast->ACLOroot, xaction);
status = COMN_ForceBeastWrite(genMsg, oldOverflowBeast, xaction);
COMN_UnlatchAndRelease(&oldOverflowBeast, XLATCHED);
if (status != zOK)
{
UNX_LATCH(&overflowBeast->ACLObeastLatch);
BST_free(overflowBeast);
RTN_PTR(NULL);
}
}
BEASTHASH_Insert(&overflowBeast->ACLOroot);
overflowBeast->ACLObstState |= BST_STATE_NEW;
overflowBeast->p.numEntries = 1;
aclEntry = &overflowBeast->acl[0];
*returnBeast = overflowBeast;
}
RTN_PTR(aclEntry);
}
/****************************************************************************
* This routine will add a new trustee and rights to the given beast
****************************************************************************/
STATUS ZAS_AddACLEntry(
GeneralMsg_s *genMsg,
AuthBeast_s *authBeast,
UserID_t *trusteeID,
NINT rights,
NINT attributes)
{
ZASAuthorizeInfo_s *authInfo;
ACLEntry_s *ACLEntry;
ZasAclOverflowBeast_s *overflowBeast;
Xaction_s *xaction;
BOOL writeMainBeast = FALSE;
Zid_t hlZid;
HardLinkBeast_s *hlBeast;
BOOL modifyMetaDataTime = TRUE;
ASSERT_MPKNSS_LOCK();
ENTER(TAUTH, ZAS_AddACLEntry);
/* Defect #306666. We can't allow unlicensed connection access */
if (!ConnectionIsLoggedIn(genMsg->pssConn.id))
{
/* They are not logged in (LICENCED), so limit their access */
SetErrno(genMsg, zERR_NO_SET_PRIVILEGE);
goto cleanupError;
}
if (authBeast->AUTHvolume->VOLenabledAttributes & zATTR_READONLY)
{
SetErrno(genMsg, zERR_VOLUME_READ_ONLY);
return zFAILURE;
}
OID_SaveObjectID(authBeast->AUTHvolume, trusteeID);
authInfo = authBeast->AUTHauthInfo.zas;
X_LATCH(&authInfo->authLatch);
/* begin the transaction for adding an ACL */
xaction = COMN_BeginXLocal(authBeast);
if ((ACLEntry = ZAS_FindTrustee(genMsg, authBeast, trusteeID,
&overflowBeast)) == NULL)
{ /* could not find the trustee */
if ((ACLEntry = ZAS_AddTrustee(genMsg, authBeast, xaction,
&writeMainBeast, &overflowBeast)) == NULL)
{ /* error */
goto cleanupUnlatch;
}
ACLEntry->rights = 0;
if (!(authBeast->AUTHattributes & zFA_SUBDIRECTORY) ||
authBeast->AUTHcomnOps.BST_isDirectoryEmpty(genMsg, &authBeast->AUTHnamed, zNTYPE_FILE))
{ /* this object has no object below it */
ZAS_RemoveEACLCacheEntry(authInfo->p.cacheIndex, authInfo->p.signature);
}
else
{
ZAS_InvalidateEntireEACLCache(genMsg, TRUE);
}
}
else
{
/*
* we need to invalidate all entries because inheritance masking can
* cause a trustee ID to not be in a cache entry that would be
* affected if a right is added that is not masked out.
*/
if (ACLEntry->rights != rights)
{ /* if it is actually changing */
ZAS_InvalidateEntireEACLCache(genMsg, TRUE);
}
}
/*
* If this is a hardlink primary beast, we need to add/remove visibility
* for all parents, not just the first parent.
*/
if ((authBeast->AUTHhardLinkZid != zINVALID_ZID) &&
!(authBeast->AUTHattributes & zFA_HARDLINK))
{
for (hlZid = authBeast->AUTHhardLinkZid; hlZid != zINVALID_ZID; )
{
hlBeast = COMN_LookupByZid(genMsg,authBeast->AUTHvolume,hlZid,
NOTLATCHED,TRUE);
if (hlBeast != NULL)
{
/*
* If rights are being given where there were none then update the
* visibility. If rights are being set to zero when they were non-zero
* before then remove the visibility. Entries that have a trustee that
* has no rights should not make directories above them visible.
*/
if (rights && !ACLEntry->rights)
{
/* FixFixFix6 -- need to do this for each parent */
ZAS_MakeItVisible(genMsg, xaction, authBeast,
hlBeast->HARDLfirstParentZid, trusteeID, 1, TRUE);
} else if (!rights && ACLEntry->rights)
{
/* FixFixFix6 -- need to remove visiblility on all parents */
ZAS_RemoveVisibility(genMsg, xaction, authBeast,
hlBeast->HARDLfirstParentZid, trusteeID, 1, TRUE);
}
hlZid = hlBeast->HARDLhardLinkZid;
COMN_Release(&hlBeast);
}
else
{
zASSERT("Broken hard link chain"==NULL);
hlZid = zINVALID_ZID;
}
}
}
else
{
zASSERT(!(authBeast->AUTHattributes & zFA_HARDLINK));
/*
* If rights are being given where there were none then update the
* visibility. If rights are being set to zero when they were non-zero
* before then remove the visibility. Entries that have a trustee that
* has no rights should not make directories above them visible.
*/
if (rights && !ACLEntry->rights)
{
/* FixFixFix6 -- need to do this for each parent */
ZAS_MakeItVisible(genMsg, xaction, authBeast,
authBeast->AUTHfirstParentZid, trusteeID, 1, TRUE);
} else if (!rights && ACLEntry->rights)
{
/* FixFixFix6 -- need to remove visiblility on all parents */
ZAS_RemoveVisibility(genMsg, xaction, authBeast,
authBeast->AUTHfirstParentZid, trusteeID, 1, TRUE);
}
}
/* fill in the ACL */
ACLEntry->trusteeID = *trusteeID;
ACLEntry->rights = rights;
ACLEntry->attributes = attributes;
if (!(authBeast->AUTHattributes & zFA_ATTR_ARCHIVE))
{
authBeast->AUTHattributes |= zFA_ATTR_ARCHIVE;
writeMainBeast = TRUE;
}
if ((modifyMetaDataTime) && (COMN_IsDerivedFrom(authBeast, zFTYPE_FILE)))
{
File_s *file = (File_s *)authBeast;
file->FILEmetaDataModifiedTime = GetUTCTime();
writeMainBeast = TRUE;
}
if (writeMainBeast || (overflowBeast == NULL))
{ /* if the main beast is dirty */
authInfo->flags |= ZAS_ALLOW_FORCED_WRITE;
COMN_MARK_BEAST_XLOCAL(&authBeast->AUTHroot, xaction);
if (COMN_ForceBeastWrite(genMsg, authBeast, xaction) != zOK)
{
authInfo->flags &= ~ZAS_ALLOW_FORCED_WRITE;
goto cleanupUnlatch;
}
authInfo->flags &= ~ZAS_ALLOW_FORCED_WRITE;
}
if (overflowBeast != NULL)
{ /* if the entry is in the overflow beast */
COMN_MARK_BEAST_XLOCAL(&overflowBeast->ACLOroot, xaction);
if (COMN_ForceBeastWrite(genMsg, overflowBeast, xaction) != zOK)
{
goto cleanupUnlatch;
}
}
if (overflowBeast != NULL)
{
COMN_UnlatchAndRelease(&overflowBeast, XLATCHED);
}
authInfo->flags |= ZAS_ALLOW_FORCED_WRITE;
VOL_insertEFLEntry(genMsg, &authBeast->AUTHroot,
EFL_FILE_STATE_MODIFY_METADATA, NULL, xaction);
authInfo->flags &= ~ZAS_ALLOW_FORCED_WRITE;
UNX_LATCH(&authInfo->authLatch);
COMN_EndXLocal(authBeast, &xaction);
RTN_STATUS(zOK);
cleanupUnlatch:
if (overflowBeast != NULL)
{
COMN_UnlatchAndRelease(&overflowBeast, XLATCHED);
}
UNX_LATCH(&authInfo->authLatch);
COMN_EndXLocal(authBeast, &xaction);
cleanupError:
RTN_STATUS(zFAILURE);
}
/****************************************************************************
* Remove a beast and link the previous to the next.
****************************************************************************/
void ZAS_RemoveOverflowBeast(
GeneralMsg_s *genMsg,
ZasAclOverflowBeast_s *delBeast,
ZasAclOverflowBeast_s *prevBeast,
ZASAuthorizeInfo_s *authInfo,
BOOL *forceMainBeast,
Xaction_s *xaction)
{
if (prevBeast == NULL)
{ /* if linked from the main beast then unlink */
authInfo->p.trusteeOverflow = delBeast->p.nextOverflowZid;
*forceMainBeast = TRUE;
}
else
{
prevBeast->p.nextOverflowZid = delBeast->p.nextOverflowZid;
COMN_MARK_BEAST_XLOCAL(&prevBeast->ACLOroot, xaction);
COMN_ForceBeastWrite(genMsg, prevBeast, xaction);
zASSERT(GetErrno(genMsg) == zOK);
ClearErrno(genMsg);
}
BST_delete(genMsg, NULL, delBeast, NULL, NULL, xaction, FALSE, TRUE);
COMN_UnlatchAndRelease(&delBeast, XLATCHED);
zASSERT(GetErrno(genMsg) == zOK);
ClearErrno(genMsg);
return;
}
/****************************************************************************
* This routine will remove a trustee from either the main beast or from
* an overflow beast.
****************************************************************************/
STATUS ZAS_RemoveTrustee(
GeneralMsg_s *genMsg,
AuthBeast_s *authBeast,
UserID_t *trusteeID,
NINT *rights,
Xaction_s *xaction)
{
ACLEntry_s *aclEntry;
Zid_t overflowZid;
Zid_t lastGoodZid = zINVALID_ZID;
ZASAuthorizeInfo_s *authInfo;
ZasAclOverflowBeast_s *deleteBeast = NULL;
ZasAclOverflowBeast_s *lastBeast = NULL;
ZasAclOverflowBeast_s *prevBeast = NULL;
STATUS status = zOK;
BOOL forceMainBeast = FALSE;
BOOL forceDeleteBeast = FALSE;
BOOL releasePrevious = FALSE;
NINT entry;
BOOL modifyMetaDataTime = TRUE;
ASSERT_MPKNSS_LOCK();
ENTER(TAUTH, ZAS_RemoveTrustee);
authInfo = authBeast->AUTHauthInfo.zas;
ASSERT_LATCH(&authInfo->authLatch);
/*
* Find the location where the trustee is to be deleted from.
*/
overflowZid = authInfo->p.trusteeOverflow;
/* search the main beast for the trustee */
for (entry=0; entry < authInfo->p.numTrusteesAssigned; entry++)
{
if (LB_GUIDCompare(&authInfo->p.ACL[entry].trusteeID, trusteeID) == 0)
{
aclEntry = &authInfo->p.ACL[entry];
forceMainBeast = TRUE;
goto findLast;
}
}
/* search the overflow beasts for the trustee */
while (overflowZid != zINVALID_ZID)
{ /* find an overflow beast with an open entry */
if (prevBeast != NULL && releasePrevious)
{
COMN_UnlatchAndRelease(&prevBeast, XLATCHED);
}
prevBeast = deleteBeast;
deleteBeast = ZAS_LookupOverflowBeast(genMsg, authBeast->AUTHvolume,
overflowZid, XLATCHED, zFTYPE_ZAS_ACL_OVERFLOW);
if (deleteBeast == NULL)
{ /* error */
status = zFAILURE;
goto cleanup;
}
lastGoodZid = overflowZid;
#if (CURRENT_BEAST_VERSION != BEAST_VERSION_3)
#error "Check to see if the beastVersion code below is still needed."
#endif
/* BEGINNING OF BEAST VERSION ONE CONVERSION CODE */
if (ZAS_ConvertACLFromVersionOne(genMsg, deleteBeast) != zOK)
{
COMN_UnlatchAndRelease(&deleteBeast, XLATCHED);
status = zFAILURE;
goto cleanup;
}
/* END OF BEAST VERSION ONE CONVERSION CODE */
overflowZid = deleteBeast->p.nextOverflowZid;
if (deleteBeast->p.numEntries == 0)
{
releasePrevious = FALSE;
ZAS_RemoveOverflowBeast(genMsg, deleteBeast, prevBeast, authInfo,
&forceMainBeast, xaction);
if (overflowZid != zINVALID_ZID)
{
deleteBeast = prevBeast;
}
else
{
deleteBeast = NULL;
}
}
else
{
releasePrevious = TRUE;
for (entry=0; entry < deleteBeast->p.numEntries; entry++)
{
if (LB_GUIDCompare(&deleteBeast->acl[entry].trusteeID, trusteeID) == 0)
{
aclEntry = &deleteBeast->acl[entry];
forceDeleteBeast = TRUE;
goto findLast;
}
}
}
}
/* could not find trustee */
SetErrno(genMsg, zERR_TRUSTEE_NOT_FOUND);
status = zFAILURE;
goto cleanup;
findLast:
/* return the rights for the trustee being deleted */
*rights = aclEntry->rights;
/*
* Find the last beast in the list of overflow beasts. The
* previous beast in the list must also be found in case we need to
* unlink it.
*/
lastBeast = deleteBeast;
while (overflowZid != zINVALID_ZID)
{ /* find the last beast */
BOOL sameBeast;
if (prevBeast != NULL && prevBeast != deleteBeast && releasePrevious)
{
COMN_UnlatchAndRelease(&prevBeast, XLATCHED);
sameBeast = FALSE;
}
else
{
sameBeast = TRUE;
}
prevBeast = lastBeast;
lastBeast = ZAS_LookupOverflowBeast(genMsg, authBeast->AUTHvolume,
overflowZid, XLATCHED, zFTYPE_ZAS_ACL_OVERFLOW);
if (lastBeast == NULL)
{ /* error */
/* Treat the last good beast as if it were the last beast */
if (lastGoodZid != zINVALID_ZID)
{
if (sameBeast)
{
lastBeast = deleteBeast;
}
else
{
lastBeast = COMN_LookupByZid(genMsg, authBeast->AUTHvolume,
lastGoodZid, XLATCHED, FALSE);
if (lastBeast == NULL)
{
/*
* This should never happen since we just found this beast on
* the last loop through.
*/
status = zFAILURE;
goto cleanup;
}
}
lastBeast->p.nextOverflowZid = zINVALID_ZID;
}
else
{
authInfo->p.trusteeOverflow = zINVALID_ZID;
}
overflowZid = zINVALID_ZID;
break;
}
lastGoodZid = overflowZid;
#if (CURRENT_BEAST_VERSION != BEAST_VERSION_3)
#error "Check to see if the beastVersion code below is still needed."
#endif
/* BEGINNING OF BEAST VERSION ONE CONVERSION CODE */
if (ZAS_ConvertACLFromVersionOne(genMsg, lastBeast) != zOK)
{
COMN_UnlatchAndRelease(&lastBeast, XLATCHED);
status = zFAILURE;
goto cleanup;
}
/* END OF BEAST VERSION ONE CONVERSION CODE */
overflowZid = lastBeast->p.nextOverflowZid;
if (lastBeast->p.numEntries == 0)
{
releasePrevious = FALSE;
ZAS_RemoveOverflowBeast(genMsg, lastBeast, prevBeast, authInfo,
&forceMainBeast, xaction);
lastBeast = prevBeast;
}
else
{
releasePrevious = TRUE;
}
}
/*
* Delete the entry by taking the last entry in the last beast and moving
* it to the deleted location.
*/
if (deleteBeast == NULL && lastBeast == NULL)
{ /* if there are no overflow records - just working on main beast*/
ZAS_DELETE_ENTRY(authInfo->p.numTrusteesAssigned, aclEntry,
authInfo->p.ACL);
forceMainBeast = TRUE;
}
else
{ /* moving entry from overflow to main */
ZAS_DELETE_ENTRY(lastBeast->p.numEntries, aclEntry, lastBeast->acl);
/*
* If the last beast is empty then get rid of it unless it was already
* reset to the previous because the "old" last beast was removed
* because it had no entries. In this case the previous beast
* was used as the last beast and we have lost track of the beast
* previous to that so we cannot remove the "new" last beast.
*/
if ((lastBeast->p.numEntries == 0) &&
(lastBeast != prevBeast))
{ /* if the last beast is empty get rid of it. */
ZAS_RemoveOverflowBeast(genMsg, lastBeast, prevBeast, authInfo,
&forceMainBeast, xaction);
if (deleteBeast == lastBeast)
{
forceDeleteBeast = FALSE;
deleteBeast = NULL;
}
lastBeast = NULL;
}
else
{
if (deleteBeast != lastBeast)
{ /* if the beast we are deleting from and the last beast are not the same then write */
COMN_MARK_BEAST_XLOCAL(&lastBeast->ACLOroot, xaction);
if (COMN_ForceBeastWrite(genMsg, lastBeast, xaction) != zOK)
{
status = zFAILURE;
goto cleanup;
}
}
}
}
if (!(authBeast->AUTHattributes & zFA_ATTR_ARCHIVE))
{
authBeast->AUTHattributes |= zFA_ATTR_ARCHIVE;
forceMainBeast = TRUE;
}
if ((modifyMetaDataTime) && (COMN_IsDerivedFrom(authBeast, zFTYPE_FILE)))
{
File_s *file = (File_s *)authBeast;
file->FILEmetaDataModifiedTime = GetUTCTime();
forceMainBeast = TRUE;
}
if (forceMainBeast)
{
authInfo->flags |= ZAS_ALLOW_FORCED_WRITE;
COMN_MARK_BEAST_XLOCAL(&authBeast->AUTHroot, xaction);
if (COMN_ForceBeastWrite(genMsg, authBeast, xaction) != zOK)
{
status = zFAILURE;
authInfo->flags &= ~ZAS_ALLOW_FORCED_WRITE;
goto cleanup;
}
authInfo->flags &= ~ZAS_ALLOW_FORCED_WRITE;
}
if (forceDeleteBeast)
{
COMN_MARK_BEAST_XLOCAL(&deleteBeast->ACLOroot, xaction);
if (COMN_ForceBeastWrite(genMsg, deleteBeast, xaction) != zOK)
{
status = zFAILURE;
goto cleanup;
}
}
cleanup:
if (deleteBeast != NULL &&
deleteBeast != lastBeast &&
deleteBeast != prevBeast)
{
COMN_UnlatchAndRelease(&deleteBeast, XLATCHED);
}
if (lastBeast != NULL &&
lastBeast != prevBeast)
{
COMN_UnlatchAndRelease(&lastBeast, XLATCHED);
}
if (prevBeast != NULL)
{
COMN_UnlatchAndRelease(&prevBeast, XLATCHED);
}
RTN_STATUS(status);
}
/****************************************************************************
*
* This routine will remove trustee and rights from a file system object.
* This function assumes that auth latch is already held.
*
****************************************************************************/
STATUS ZAS_RemoveLatchedACLEntry(
GeneralMsg_s *genMsg,
AuthBeast_s *authBeast,
UserID_t *trusteeID,
NINT purgedFileFlag,
Xaction_s *xaction)
/* FixFixFix6 --
* need to do the right thing when files are going to salvage */
{
ZASAuthorizeInfo_s *authInfo;
Xaction_s *localXaction;
NINT rights;
Zid_t hlZid;
HardLinkBeast_s *hlBeast;
ASSERT_MPKNSS_LOCK();
authInfo = authBeast->AUTHauthInfo.zas;
/* begin the transaction for removing an ACL */
if (xaction == NULL)
{
zASSERT(!(authBeast->AUTHbstState & BST_STATE_XLOCAL));
localXaction = COMN_BeginXLocal(authBeast);
}
else
{
localXaction = xaction;
}
if (ZAS_RemoveTrustee(genMsg, authBeast, trusteeID, &rights,
localXaction) != zOK)
{
goto cleanup;
}
/*
* Remove visibility if the trustee was giving some type of rights.
*/
if (rights)
{
/*
* If this is a hardlink primary beast, we need to add/remove visibility
* for all parents, not just the first parent.
*/
if ((authBeast->AUTHhardLinkZid != zINVALID_ZID) &&
!(authBeast->AUTHattributes & zFA_HARDLINK))
{
for (hlZid = authBeast->AUTHhardLinkZid; hlZid != zINVALID_ZID; )
{
hlBeast = COMN_LookupByZid(genMsg,authBeast->AUTHvolume,hlZid,
NOTLATCHED,TRUE);
if (hlBeast != NULL)
{
ZAS_RemoveVisibility(genMsg, localXaction, authBeast,
hlBeast->HARDLfirstParentZid, trusteeID, 1, TRUE);
hlZid = hlBeast->HARDLhardLinkZid;
COMN_Release(&hlBeast);
}
else
{
zASSERT("Broken hard link chain"==NULL);
hlZid = zINVALID_ZID;
}
}
}
else
{
zASSERT(!(authBeast->AUTHattributes & zFA_HARDLINK));
ZAS_RemoveVisibility(genMsg, localXaction, authBeast,
authBeast->AUTHfirstParentZid, trusteeID, 1, TRUE);
}
}
if (!(authBeast->AUTHattributes & zFA_SUBDIRECTORY) ||
authBeast->AUTHcomnOps.BST_isDirectoryEmpty(genMsg, &authBeast->AUTHnamed, zNTYPE_FILE))
{ /* this object has no objects below it */
authInfo->p.cacheIndex = INVALID_EACL_CACHE_INDEX; /* invalidate the cache pointer */
}
else
{
ZAS_InvalidateEACLCacheEntries(genMsg, trusteeID, TRUE);
}
authInfo->flags |= ZAS_ALLOW_FORCED_WRITE;
VOL_insertEFLEntry(genMsg, &authBeast->AUTHroot,
EFL_FILE_STATE_MODIFY_METADATA, NULL, localXaction);
authInfo->flags &= ~ZAS_ALLOW_FORCED_WRITE;
if (xaction == NULL)
{
COMN_EndXLocal(authBeast, &localXaction);
}
return zOK;
cleanup:
if (xaction == NULL)
{
COMN_EndXLocal(authBeast, &localXaction);
}
return zFAILURE;
}
/****************************************************************************
*
* This routine will remove trustee and rights from a file system object
*
****************************************************************************/
STATUS ZAS_RemoveACLEntry(
GeneralMsg_s *genMsg,
AuthBeast_s *authBeast,
UserID_t *trusteeID,
NINT purgedFileFlag)
/* FixFixFix6 --
* need to do the right thing when files are going to salvage */
{
ZASAuthorizeInfo_s *authInfo;
STATUS status = zFAILURE;
ASSERT_MPKNSS_LOCK();
ENTER(TAUTH, ZAS_RemoveACLEntry);
/* Defect #306666. We can't allow unlicensed connection access */
if (!ConnectionIsLoggedIn(genMsg->pssConn.id))
{
/* They are not logged in (LICENCED), so limit their access */
SetErrno(genMsg, zERR_NO_TRUSTEE_CHANGE_PRIVILEGE);
goto cleanupError;
}
if (authBeast->AUTHvolume->VOLenabledAttributes & zATTR_READONLY)
{
SetErrno(genMsg, zERR_VOLUME_READ_ONLY);
return zFAILURE;
}
authInfo = authBeast->AUTHauthInfo.zas;
X_LATCH(&authInfo->authLatch);
status = ZAS_RemoveLatchedACLEntry(genMsg, authBeast, trusteeID,
purgedFileFlag, NULL);
UNX_LATCH(&authInfo->authLatch);
cleanupError:
RTN_STATUS(status);
}
/****************************************************************************
* This routine will return the effective rights for a beast using the
* IDs in the connection structure.
****************************************************************************/
STATUS ZAS_GetEffectiveRights(
GeneralMsg_s *genMsg,
AuthBeast_s *authBeast,
Zid_t parentZID,
NINT *effectiveRights)
{
NSSConnection_s *pssConn;
STATUS status;
ASSERT_MPKNSS_LOCK();
ENTER(TAUTH, ZAS_GetEffectiveRights);
if ((pssConn = CNCT_RESOLVE_CONNECTION(genMsg)) == NULL)
RTN_STATUS(zFAILURE);
// Removed because supervisor should not be able to see directories that are
// marked for connection zero only
//
// if (pssConn->privileges & SUPERVISOR)
// { /* if the connection has supervisor privilege allow all rights */
// *effectiveRights = -1;
// RTN_STATUS(zOK);
// }
/*
* NDS can call back into the file system while it is resolving a
* connection. In this case the authListLatch is already held and we
* will deadlock. To avoid this we check to see we are on connection
* zero and if the condition exist that would indicate we are trying
* to resolve this connection. If so we give it rights to continue.
*/
if ((genMsg->pssConn.id == zSYS_CONNECTION) &&
IS_XLATCHED(&pssConn->authInfo.authListLatch) &&
(CNCT_LatchingConnection == zSYS_CONNECTION))
{
*effectiveRights = zVALID_TRUSTEE_RIGHTS;
RTN_STATUS(zOK);
}
S_LATCH(&genMsg->pssConn.ptr->authInfo.authListLatch);
status = ZAS_GetEffectiveRightsByIDs(genMsg, authBeast, parentZID,
(genMsg->pssConn.ptr->flags & CNCTFL_SECURE_ACCESS) ? TRUE : FALSE,
IsSupervisor(genMsg->pssConn.id),
genMsg->pssConn.ptr->authInfo.numAuthenticatedIDs,
&genMsg->pssConn.ptr->authInfo.authenticatedIDs[0],
effectiveRights);
UNS_LATCH(&genMsg->pssConn.ptr->authInfo.authListLatch);
RTN_STATUS(status);
}
/****************************************************************************
* Re-create the visibility lists
****************************************************************************/
void ZAS_RebuildVisibilityLists(
GeneralMsg_s *genMsg,
Volume_s *vol,
Zid_t *zidArray,
NINT numArrayEntries,
VisRebuildStats_s *stats,
unicode_t *name)
{
Zid_t startingZid = 0;
NINT numReturnedZids;
RootBeast_s *beast;
NINT index;
QUAD totalBeasts;
STATUS status;
Zid_t hlZid;
HardLinkBeast_s *hlBeast;
/*
* Go through the entire beast tree and re-add all trustees
*/
aprintf(YELLOW,
MSG("Visbility rebuild: Rebuilding visiblity information on %U\n", 206),
name);
totalBeasts = 0;
vol->VOLzidInProcess = 0;
vol->v_statusFlag |= VOL_SF_CLEAN_VIS_REBUILD;
do
{
/*
* Check to see if someone is wanting to deactivate the volume.
* If so we stop our thread so the volume can be deactivated.
*/
if (vol->v_statusFlag & VOL_SF_LEAVING_ACTIVE_STATE_CLEANUP)
{
aprintf(LRED,
MSG("STOPPING VISIBILITY REBUILD ON %U BECAUSE OF VOLUME DEACTIVATE\n", 241),
name);
goto exit;
}
if (vol->VOLcomnVolOps.VOL_browseBeastsInVolume(genMsg,
vol, SELECT_BEASTS_ALL, numArrayEntries, &startingZid, zidArray,
&numReturnedZids) != zOK)
{
aprintf(LRED, MSG("Visibility rebuild on volume %U:\n"
"Error %d getting object list while adding visibility.\n", 244),
name, GetErrno(genMsg));
goto exit;
}
/* Process each entry */
for (index = 0; index < numReturnedZids; index++)
{
totalBeasts++;
if (!(totalBeasts % 10000))
{
aprintf(LGREEN,
"(%U) Visibility rebuild pass 2: %Ld objects processed\n",
name, totalBeasts);
}
vol->VOLzidInProcess = zidArray[index];
if ((beast = COMN_LookupByZid(genMsg, vol,
zidArray[index], SLATCHED, TRUE)) == NULL)
{
zASSERT(GetErrno(genMsg) != 20000);
/*
* Only report an error if it not one of errors we know
* can happen because of timing with beast delete.
*/
if (GetErrno(genMsg) != zERR_INVALID_BEAST_ID &&
GetErrno(genMsg) != zERR_INVALID_BEAST_ID)
{
aprintf(LRED, MSG("Visibility rebuild on volume %U:\n"
"Error %d looking up an object. ZID[%d]=%Ld\n", 247),
name, GetErrno(genMsg), index, zidArray[index]);
}
ClearErrno(genMsg);
continue;
}
/*
* If this is a normal file/dir then processes any trustees
*/
if ((COMN_IsDerivedFrom(beast, zFTYPE_FILE)) &&
(!(((File_s *)beast)->FILEattributes & zFA_HARDLINK)))
{
/*
* If this is a hardlink primary beast, we need to add/remove visibility
* for all parents, not just the first parent.
*/
if (((File_s *)beast)->FILEhardLinkZid != zINVALID_ZID)
{
for (hlZid = ((File_s *)beast)->FILEhardLinkZid; hlZid != zINVALID_ZID; )
{
hlBeast = COMN_LookupByZid(genMsg,beast->ROOTvolume,
hlZid,NOTLATCHED,TRUE);
if (hlBeast != NULL)
{
if ((status = ZAS_AddBeastVisibility(genMsg,
(AuthBeast_s *)beast, ((File_s *)hlBeast)->FILEfirstParentZid,
FALSE, stats, FALSE)) != zOK)
{
aprintf(LRED, MSG("Visibility rebuild on volume %U:\n"
"Error %d looking up an object while adding visibility.\n",249),
name, GetErrno(genMsg));
}
hlZid = hlBeast->HARDLhardLinkZid;
COMN_Release(&hlBeast);
}
else
{
zASSERT("Broken hard link chain"==NULL);
hlZid = zINVALID_ZID;
}
}
}
else
{
if ((status = ZAS_AddBeastVisibility(genMsg,
(AuthBeast_s *)beast, ((File_s *)beast)->FILEfirstParentZid,
FALSE, stats, FALSE)) != zOK)
{
aprintf(LRED, MSG("Visibility rebuild on volume %U:\n"
"Error %d looking up an object while adding visibility.\n", 249),
name, GetErrno(genMsg));
}
}
}
COMN_UnlatchAndRelease(&beast, SLATCHED);
}
} while (numReturnedZids > 0);
exit:
vol->v_statusFlag &= ~VOL_SF_CLEAN_VIS_REBUILD;
ClearErrno(genMsg);
return;
}
/****************************************************************************
* The thread to rebuild the visibility list for the given volume
****************************************************************************/
void ZAS_VisibilityRebuildThread(
FsmLite_s *fsm,
VisRebParms_s *parms)
{
enum
{
NUM_REQUESTED_ZIDS = 100
};
GeneralMsg_s genMsg;
Zid_t startingZid = 0;
Zid_t *zidArray;
NINT numReturnedZids;
RootBeast_s *beast;
NINT index;
Xaction_s *xaction;
ZASAuthorizeInfo_s *authInfo;
VisRebuildStats_s stats;
QUAD totalBeasts;
Volume_s *vol = parms->vol;
COMN_SETUP_GENERAL_MSG_NOSA(&genMsg);
COMN_LockVolumeActive(&genMsg, vol, FALSE);
zidArray = malloc(NUM_REQUESTED_ZIDS * sizeof(Zid_t));
if (zidArray == NULL)
{
aprintf(LRED,
MSG("Visibility rebuild on volume %U:\n"
"Unable to get enough memory to complete the rebuild.\n", 250),
parms->name);
goto exit;
}
stats.VisNumBeasts = 0;
stats.VisNumOverflowRemoved = 0;
stats.VisNumFilesCleaned = 0;
stats.VisNumTrusteesProcessed = 0;
/*
* Go through the entire beast tree and remove all visibility information.
*/
aprintf(YELLOW,
MSG("Visibility rebuild: Removing visiblity information from %U\n", 251),
parms->name);
totalBeasts = 0;
do
{
/*
* Check to see if someone is wanting to deactivate the volume.
* If so we stop our thread so that the volume can be deactivated.
*/
if (vol->v_statusFlag & VOL_SF_LEAVING_ACTIVE_STATE_CLEANUP)
{
aprintf(LRED,
MSG("STOPPING VISIBILITY REBUILD ON %U BECAUSE OF VOLUME DEACTIVATE\n", 252),
parms->name);
goto exitStats;
}
if (vol->VOLcomnVolOps.VOL_browseBeastsInVolume(&genMsg,
vol, SELECT_BEASTS_ALL, NUM_REQUESTED_ZIDS,
&startingZid, zidArray, &numReturnedZids) != zOK)
{
aprintf(LRED,
MSG("Visibility rebuild on volume %U:\n"
"Error %d getting object list.\n", 253), parms->name,
GetErrno(&genMsg));
goto exitFreeMem;
}
/* Process each entry */
for (index = 0; index < numReturnedZids; index++)
{
totalBeasts++;
if (!(totalBeasts % 10000))
{
aprintf(LGREEN,
"(%U) Visibility rebuild pass 1: %Ld objects processed\n",
parms->name, totalBeasts);
}
if ((beast = COMN_LookupByZid(&genMsg, vol,
zidArray[index], XLATCHED, TRUE)) == NULL)
{
zASSERT(GetErrno(&genMsg) != 20000);
aprintf(LRED, MSG("Visibility rebuild on volume %U:\n"
"Error %d looking up an object. ZID[%d]=%Ld\n", 254),
parms->name, GetErrno(&genMsg), index, zidArray[index]);
ClearErrno(&genMsg);
continue;
}
stats.VisNumBeasts++;
/*
* If this is a visibility overflow beast then just get rid of it.
*/
if (beast->ROOTbeastClass->classID == zFTYPE_ZAS_VIS_OVERFLOW)
{
xaction = COMN_BeginXLocal(beast);
if (BST_delete(&genMsg, NULL, beast, NULL, NULL, xaction,
FALSE, TRUE) != zOK)
{
ClearErrno(&genMsg);
zASSERT("Failed to delete trustee overflow beast"==NULL);
}
COMN_EndXLocal(beast, &xaction);
COMN_UnlatchAndRelease(&beast, XLATCHED);
stats.VisNumOverflowRemoved++;
continue;
}
/*
* If this is a normal file/dir then get rid of the visibility
* information.
*/
if (COMN_IsDerivedFrom(beast, zFTYPE_FILE))
{
authInfo = ((AuthBeast_s *)beast)->AUTHauthInfo.zas;
/* If there are visibility entries then clear them */
if (authInfo->p.numVisibilityTrusteesAssigned ||
authInfo->p.visibilityOverflow)
{
zASSERT(!authInfo->p.visibilityOverflow ||
authInfo->p.numVisibilityTrusteesAssigned == 4);
authInfo->p.numVisibilityTrusteesAssigned = 0;
authInfo->p.visibilityOverflow = zINVALID_ZID;
xaction = COMN_BeginXLocal(beast);
COMN_MARK_BEAST_XLOCAL(beast, xaction);
COMN_ForceBeastWrite(&genMsg, beast, xaction);
COMN_EndXLocal(beast, &xaction);
stats.VisNumFilesCleaned++;
}
}
COMN_UnlatchAndRelease(&beast, XLATCHED);
}
} while (numReturnedZids > 0);
/* Rebuild the visibility lists */
ZAS_RebuildVisibilityLists(&genMsg, vol, zidArray, NUM_REQUESTED_ZIDS,
&stats, parms->name);
exitStats:
aprintf(LCYAN, MSG( "Visibility rebuild finished on volume %U\n"
"Objects examined: %Ld\n"
"Objects cleaned: %Ld\n"
"Overflow objects removed: %Ld\n"
"Trustees re-added: %Ld\n", 255),
parms->name,
stats.VisNumBeasts,
stats.VisNumFilesCleaned,
stats.VisNumOverflowRemoved,
stats.VisNumTrusteesProcessed);
exitFreeMem:
free(zidArray);
exit:
vol->v_statusFlag &= ~VOL_SF_CLEAN_VIS_SCHEDULED;
COMN_UnlockVolumeActive(vol, FALSE);
free(parms);
free(fsm);
return;
}
/****************************************************************************
* Rebuild the visibility list for the given volume
****************************************************************************/
void ZAS_VisibilityRebuild(
GeneralMsg_s *genMsg,
Volume_s *vol,
unicode_t *name)
{
VisRebParms_s *parms;
FsmLite_s *fsm;
#if NSS_DEBUG IS_ENABLED
STATIC NINT fsmInstance = 0;
#endif
if (vol->state != zVOLSTATE_ACTIVE)
{
aprintf(LRED, MSG("Volume %U must be active to "
"rebuild visibility.\n", 297), name);
goto exit;
}
/* Check to see if thes volume has the ZAS auth model running on it */
if (vol->p.authModelID != zFTYPE_ZAS_AUTH_MODEL)
{
aprintf(LRED, MSG("Volume %U does not use visibility lists\n", 298),
name);
goto exit;
}
/* Check to see if it is already running */
if (vol->VOLv_statusFlag & VOL_SF_CLEAN_VIS_SCHEDULED)
{ /* There is already one running */
aprintf(LRED, MSG("Volume %U is already rebuilding visibility.\n", 299),
name);
goto exit;
}
vol->v_statusFlag |= VOL_SF_CLEAN_VIS_SCHEDULED;
/* Start up a seperate thread to do the processing */
fsm = malloc(sizeof(FsmLite_s));
if (fsm == NULL)
{
aprintf(LRED, MSG("Not enough memory to start visibility rebuild\n",
300));
vol->v_statusFlag &= ~VOL_SF_CLEAN_VIS_SCHEDULED;
goto exit;
}
/* Setup parameters for thread */
parms = malloc(sizeof(VisRebParms_s));
if (parms == NULL)
{
aprintf(LRED, MSG("Not enough memory to start visibility rebuild\n",
301));
vol->v_statusFlag &= ~VOL_SF_CLEAN_VIS_SCHEDULED;
free(fsm);
goto exit;
}
parms->vol = vol;
unicpy(parms->name, name);
FSMLITE_INIT(fsm, "FSM for visibility rebuild ", ++fsmInstance);
WORK_Schedule(fsm, ZAS_VisibilityRebuildThread, (ADDR)parms);
aprintf(WHITE,
MSG("Visibility rebuild started on volume \"%U\".\n",302), name);
exit:
ClearErrno(genMsg);
return;
}
/****************************************************************************
* Process command line to start rebuilding of a volumes visibility list.
****************************************************************************/
void ZAS_VisibilityRebuildByName(
GeneralMsg_s *genMsg,
unicode_t *name)
{
Volume_s *vol;
Volume_s *adminVol;
typedef struct Stack_s {
unicode_t volName[zMAX_COMPONENT_NAME];
} Stack_s;
STACK_ALLOC();
adminVol = COMN_GetAdminVolume();
/*
* See if doing ALL volumes
*/
if (uniicmp(name, MSGNot(L"all")) == 0)
{
DQ_FOREACH(&NSSMasterVolumeList, vol, Volume_s, masterVolLink)
{
if (vol != adminVol) /* skip the ADMIN volume */
{
COMN_GetVolumeName(genMsg, vol, aStack->volName, sizeof(aStack->volName));
COMN_USE_BEAST(&vol->VOLroot);
(void)ZAS_VisibilityRebuild(genMsg, vol, aStack->volName);
BST_UNUSE_BEAST(&vol->VOLroot);
}
}
}
else
{
/*
* Change the given volume
*/
vol = COMN_VolumeNameLookup(genMsg, name, FALSE, NULL);
if (vol == NULL)
{
errPrintf(WHERE, Module, 0,
MSG("Volume %U not found. Check your spelling and type NSS /volumes.\n", 303), name);
STACK_FREE();
return;
}
if (vol == adminVol)
{
BST_UNUSE_BEAST(&vol->VOLroot);
STACK_FREE();
return;
}
ZAS_VisibilityRebuild(genMsg, vol, name);
BST_UNUSE_BEAST(&vol->VOLroot); /* remove useCount added by lookup*/
}
STACK_FREE();
return;
}
/****************************************************************************
* This routine will return the effective rights for a beast using the
* IDs in the connection structure.
****************************************************************************/
STATUS ZAS_GetParentsEffectiveRights(
GeneralMsg_s *genMsg,
AuthBeast_s *authBeast,
Zid_t parentZID,
NINT *effectiveRights)
{
NSSConnection_s *pssConn;
AuthBeast_s *parentBeast;
STATUS status;
ENTER(TAUTH, ZAS_GetEffectiveRights);
if ((pssConn = CNCT_RESOLVE_CONNECTION(genMsg)) == NULL)
{
RTN_STATUS(zFAILURE);
}
// Removed because supervisor should not be able to see directories that are
// marked for connection zero only
//
// if ( IsSupervisor(genMsg->pssConn.id)
// { /* if the connection has supervisor privilege allow all rights */
// *effectiveRights = -1;
// RTN_STATUS(zOK);
// }
/* Open the parent */
if (parentZID != zINVALID_ZID)
{
parentBeast = (AuthBeast_s *)BEASTHASH_LookupByZid(genMsg,
authBeast->AUTHvolume, parentZID, NOTLATCHED);
if (parentBeast == NULL)
{
RTN_STATUS(zFAILURE);
}
}
else
{ /* at the root */
effectiveRights = 0; /* the root's parent has no rights */
RTN_STATUS(zOK);
}
parentZID = parentBeast->AUTHfirstParentZid;
/*
* NDS can call back into the file system while it is resolving a
* connection. In this case the authListLatch is already held and we
* will deadlock. To avoid this we check to see we are on connection
* zero and if the condition exist that would indicate we are trying
* to resolve this connection. If so we give it rights to continue.
*/
if ((genMsg->pssConn.id == zSYS_CONNECTION) &&
IS_XLATCHED(&pssConn->authInfo.authListLatch) &&
(CNCT_LatchingConnection == zSYS_CONNECTION))
{
*effectiveRights = zVALID_TRUSTEE_RIGHTS;
RTN_STATUS(zOK);
}
S_LATCH(&genMsg->pssConn.ptr->authInfo.authListLatch);
status = ZAS_GetEffectiveRightsByIDs(genMsg, parentBeast, parentZID,
(genMsg->pssConn.ptr->flags & CNCTFL_SECURE_ACCESS) ? TRUE : FALSE,
IsSupervisor(genMsg->pssConn.id),
genMsg->pssConn.ptr->authInfo.numAuthenticatedIDs,
&genMsg->pssConn.ptr->authInfo.authenticatedIDs[0],
effectiveRights);
UNS_LATCH(&genMsg->pssConn.ptr->authInfo.authListLatch);
COMN_Release(&parentBeast);
RTN_STATUS(status);
}
/****************************************************************************
* This routine will return all the effective rights for a beast. If it is
* successful it returns a malloc'ed structure that must be freed by the caller.
****************************************************************************/
STATUS ZAS_GetEffectiveACL(
GeneralMsg_s *genMsg,
AuthBeast_s *authBeast,
Zid_t parentZID,
AuthCacheNode_s **effectiveACL,
BOOL canBlock,
BOOL *freeEACL)
{
AuthCacheNode_s *computedEACL;
AuthCacheNode_s *newEACL;
AuthCacheNode_s *newerEACL;
AuthBeast_s *beastMemory[BEAST_STACK_ALLOC_SIZE];
AuthBeast_s *(*beastStack)[];
STATUS status;
AuthBeast_s *parentBeast;
AuthBeast_s *originalBeast;
NINT stackPtr = 0;
NINT tempStackPtr;
NINT sequence;
UserID_t trusteeID;
NINT rights;
NINT attributes;
NINT index;
NINT numACLs;
NINT numACLslots;
NINT maxStackEntries = BEAST_STACK_ALLOC_SIZE;
NINT originalResetCount = 999;
BOOL freeEACLFlag = FALSE;
BOOL cacheLatched = FALSE;
ASSERT_MPKNSS_LOCK();
#if NSS_DEBUG IS_ENABLED
AuthERRequests++;
#endif
*effectiveACL = NULL;
*freeEACL = FALSE;
/*
* If this beast comes from the persistent admin volume but its zid
* is too low then we are getting its parent from the regular admin
* volume. Change the parent to the first parent of the beast.
*/
if ((authBeast->AUTHvolume == PersistAdminVolume) && (parentZID <
AVOL_FIRST_PERSISTENT_ZID))
{
parentZID = authBeast->AUTHfirstParentZid;
}
/*
* The beast must be latched when coming into this routine. It may be
* uplatched during part of the routine, but it will be returned to the
* same latch state it started at.
*/
beastStack = &beastMemory;
COMN_USE_BEAST(&authBeast->AUTHroot);
originalBeast = authBeast;
/*
* Search the full path (backwards) for the first beast with a valid
* effective ACL. If there is no effective ACL in a beast then push
* its ZID on the stack and keep looking.
*/
for(;;)
{
//X_LATCH(&authBeast->AUTHauthInfo.zas->authLatch);
X_LATCH(&AuthCache.latch);
originalResetCount = AuthCache.resetCount;
/*
* As a performance enhancement we first check if the
* beast's restartCount is still valid. If the Beast
* does not match the the activation count then the
* beast is 'old' and must not be in the cache.
*/
if ( authBeast->AUTHvolume->v_restartCount ==
authBeast->AUTHauthInfo.zas->p.restartCount )
{ /* Beast is at correct activation count so see if auth info is
* in the cache. */
computedEACL = ZAS_GetEACLCacheEntry(
authBeast->AUTHauthInfo.zas->p.cacheIndex,
authBeast->AUTHauthInfo.zas->p.signature);
}
else
{ /* Must init because this is used twice more */
computedEACL = NULL;
}
if (computedEACL != NULL)
{ /* found an effective ACL */
#if NSS_DEBUG IS_ENABLED
AuthERHits++;
#endif
//UNX_LATCH(&authBeast->AUTHauthInfo.zas->authLatch);
/*
* We can avoid doing this latch as long as we can be sure that
* we will not block while using computedEACL. Since the code
* that requires the latch is in the loop for processing
* stack entries, we should be able to avoid the latch if we are
* not going into that loop.
*/
// if (stackPtr > 0)
// {
// X_LATCH(&AuthCache.latch);
// cacheLatched = TRUE;
// }
COMN_Release(&authBeast);
cacheLatched = TRUE;
break; /* exit the loop */
}
UNX_LATCH(&AuthCache.latch);
//X_LATCH(&authBeast->AUTHauthInfo.zas->authLatch);
/* no EACL in the cache -- add to the stack */
ZAS_PUSH_BEAST(status, errorSet, authBeast, stackPtr, maxStackEntries,
beastMemory, beastStack);
if (parentZID != zINVALID_ZID)
{
parentBeast = (AuthBeast_s *)BEASTHASH_LookupByZid(genMsg,
authBeast->AUTHvolume, parentZID, NOTLATCHED);
if (parentBeast == NULL)
{
status = zERR_UNABLE_TO_OPEN_BEAST;
goto errorSet;
}
}
else
{ /* at the root */
zASSERT(authBeast->AUTHfirstParentZid == zINVALID_ZID ||
COMN_IsDerivedFrom(&authBeast->AUTHroot, zFTYPE_VOLUME));
break;
}
authBeast = parentBeast;
parentZID = authBeast->AUTHfirstParentZid;
}
/* compute effective ACLs for each beast on the stack and put them in
* the cache. */
tempStackPtr = stackPtr;
while (tempStackPtr > 0)
{ /* while there are entries on the ZID stack */
authBeast = (*beastStack)[--tempStackPtr];
numACLs = 0;
/* allocate a buffer for a new cache entry */
if (computedEACL == NULL)
{ /* did not find EACL -- don't put anything in the new one */
newEACL = malloc(sizeof(AuthCacheNode_s));
if (newEACL == NULL)
{ /* out of memory */
status = zERR_NO_MEMORY;
goto errorSet;
}
numACLslots = 1;
}
else
{
numACLslots = computedEACL->EACL.numEntries;
newEACL = (AuthCacheNode_s *)malloc(EACL_SIZE(numACLslots));
if (newEACL == NULL)
{ /* out of memory */
status = zERR_NO_MEMORY;
goto errorSet;
}
memcpy(newEACL, computedEACL, sizeof(AuthCacheNode_s) - sizeof(EffectiveACL_s));
/* apply the inherited rights mask and inheritance flags*/
for (index = 0; index < computedEACL->EACL.numEntries; index++)
{
if (computedEACL->EACL.entry[index].attributes &
zAUTHORIZE_INHERIT_DOWN)
{
newEACL->EACL.entry[numACLs].rights =
(computedEACL->EACL.entry[index].rights &
authBeast->AUTHauthInfo.zas->p.inheritedRightsMask) &
zVALID_TRUSTEE_RIGHTS; /* strip off special rights as well*/
if (newEACL->EACL.entry[numACLs].rights != 0)
{ /* if there are rights assigned */
newEACL->EACL.entry[numACLs].trusteeID =
computedEACL->EACL.entry[index].trusteeID;
newEACL->EACL.entry[numACLs].attributes =
computedEACL->EACL.entry[index].attributes;
numACLs++;
}
}
}
}
if (freeEACLFlag)
{ /* if the computed EACL has not been assigned to the cache then free it */
free(computedEACL);
freeEACLFlag = FALSE;
}
if (cacheLatched)
{
UNX_LATCH(&AuthCache.latch);
cacheLatched = FALSE;
}
newEACL->EACL.numEntries = numACLs;
/* FixFixFix6 -- check on multi-domain NDS considerations */
newEACL->domainID = 0;
/* merge in the ACLs from this beast */
/* FixFixFix6 -- have not considered negative ACLs */
sequence = 0;
while (sequence != -1)
{ /* while there are still ACL entries */
if (ZAS_GetAnACL(genMsg, authBeast, &sequence, &trusteeID, &rights,
&attributes) != zOK)
{
status = GetErrno(genMsg);
goto errorSet;
}
if (sequence == -1)
{ /* no more entries */
break;
}
/*
* If this is the special secure user then setup special rights.
*/
if (LB_GUIDCompare(&trusteeID, &zSECURE_CONNECTION_USERID) == 0)
{
rights |= (zAUTHORIZE_ACCESS_CONTROL | zAUTHORIZE_SECURE);
free(newEACL);
newEACL = malloc(sizeof(AuthCacheNode_s));
if (newEACL == NULL)
{ /* out of memory */
status = zERR_NO_MEMORY;
goto errorSet;
}
numACLs = 0;
index = 0;
numACLslots = 1;
sequence = -1; /* don't do any more */
}
else
{
for (index = 0; index < numACLs; index++)
{ /* search the current EACL entries */
if (LB_GUIDCompare(&newEACL->EACL.entry[index].trusteeID, &trusteeID) == 0)
{ /* The trustee is already in the effective ACL */
/* Don't lose supervisor rights */
newEACL->EACL.entry[index].rights &= zAUTHORIZE_SUPERVISOR;
newEACL->EACL.entry[index].rights |= rights;
newEACL->EACL.entry[index].attributes = attributes;
goto nextEntry;
}
else if (LB_GUIDCompare(&newEACL->EACL.entry[index].trusteeID, &trusteeID) > 0)
{ /* need to insert a new entry */
break;
}
}
}
/**/
/* insert a new entry */
/**/
/* make more room to insert a new entry -- if we need to */
if (numACLs == numACLslots)
{
newerEACL = realloc(newEACL,
EACL_SIZE(numACLs + EACL_GROW_AMOUNT));
if (newerEACL == NULL)
{
free(newEACL);
status = zERR_NO_MEMORY;
goto errorSet;
}
newEACL = newerEACL;
numACLslots = numACLs + EACL_GROW_AMOUNT;
}
/* keep in sorted order */
if (index < numACLs)
{ /* need to insert, so shift the entries up by one */
memmove(&newEACL->EACL.entry[index+1],
&newEACL->EACL.entry[index],
sizeof(ACLEntry_s)*(numACLs-index));
}
newEACL->EACL.entry[index].trusteeID = trusteeID;
newEACL->EACL.entry[index].rights = rights;
newEACL->EACL.entry[index].attributes = attributes;
numACLs++;
nextEntry:
continue;
}
if (numACLs < numACLslots)
{
if (numACLs > 0)
{ /* if there are still some EACL entries */
/* resize the EACL to the needed size */
newerEACL = realloc(newEACL, EACL_SIZE(numACLs));
if (newerEACL == 0)
{
status = zERR_NO_MEMORY;
goto errorSet;
}
newEACL = newerEACL;
}
}
newEACL->EACL.numEntries = numACLs;
X_LATCH(&AuthCache.latch);
cacheLatched = TRUE;
if ((newerEACL = ZAS_AddEACLCacheEntry(newEACL, originalResetCount,
&authBeast->AUTHauthInfo.zas->p.cacheIndex)) != NULL)
{
authBeast->AUTHauthInfo.zas->p.signature = newerEACL->signature;
authBeast->AUTHauthInfo.zas->p.restartCount =
authBeast->AUTHvolume->v_restartCount;
freeEACLFlag = FALSE;
computedEACL = newerEACL;
}
else
{
authBeast->AUTHauthInfo.zas->p.cacheIndex = INVALID_EACL_CACHE_INDEX;
freeEACLFlag = TRUE;
computedEACL = newEACL;
}
}
if (cacheLatched)
{
#if NSS_DEBUG IS_ENABLED
AuthERImmediateHits++;
#endif
UNX_LATCH(&AuthCache.latch);
cacheLatched = FALSE;
}
/*
* If the computed EACL has not been assigned to cache then pass it
* back to the caller. If it is assigned to the cache and the caller
* can block before using it then we need to make a copy because it can
* be released from the cache as soon as we yield.
*/
if (freeEACLFlag)
{
*effectiveACL = computedEACL;
*freeEACL = TRUE;
freeEACLFlag = FALSE;
}
else
{ /* It has been assigned to the cache */
if (canBlock)
{
int size = EACL_SIZE(computedEACL->EACL.numEntries);
*effectiveACL = malloc(size);
if (*effectiveACL == NULL)
{ /* out of memory */
status = zERR_NO_MEMORY;
goto errorSet;
}
memcpy(*effectiveACL, computedEACL, size);
*freeEACL = TRUE;
}
else
{
*effectiveACL = computedEACL;
*freeEACL = FALSE;
}
}
status = zOK;
exit:
ZAS_CLEANUP_BEAST_STACK(stackPtr, maxStackEntries, beastStack);
if (freeEACLFlag)
{ /* if the computed EACL has not been assigned to the cache or is
* not being returned to the caller then free it */
free(computedEACL);
}
if (cacheLatched)
{
UNX_LATCH(&AuthCache.latch);
cacheLatched = FALSE;
}
return status;
errorSet:
SetErrno(genMsg, status);
status = zFAILURE;
goto exit;
}
/****************************************************************************
* This routine will return the effective rights for a beast given an array
* of authenticated IDs.
****************************************************************************/
STATUS ZAS_GetEffectiveRightsByIDs(
GeneralMsg_s *genMsg,
AuthBeast_s *authBeast,
Zid_t parentZID,
BOOL secureAccess,
BOOL supervisor,
NINT numIDs,
UserID_t *IDs,
NINT *effectiveRights)
{
AuthCacheNode_s *computedEACL;
NINT numEntries;
NINT index;
NINT connectIndex;
SNINT compare;
BOOL freeEACL;
ASSERT_MPKNSS_LOCK();
ENTER(TAUTH, ZAS_GetEffectiveRightsByIDs);
/*
* IMPORTANT: Do not block after calling this function. The returned
* computed EACL can be in the cache and the cache is not latched at this
* point in time.
*/
if (ZAS_GetEffectiveACL(genMsg, authBeast, parentZID, &computedEACL, FALSE,
&freeEACL) != zOK)
{
goto error;
}
numEntries = computedEACL->EACL.numEntries;
if (supervisor)
{
*effectiveRights = zVALID_TRUSTEE_RIGHTS;
}
else
{
*effectiveRights = 0;
}
if (numEntries > 0)
{ /* if there are any entries in the effective ACL */
/*
* If the first entry in the EACL is the special connection zero
* trustee then it takes precedence over all other entries. It
* means only connection zero access is allowed and given the
* specified rights.
*/
if (LB_GUIDCompare(&computedEACL->EACL.entry[0].trusteeID,
&zSECURE_CONNECTION_USERID) == 0)
{
if (secureAccess || (genMsg->flags & ALLOW_SECURE_ACCESS))
{
*effectiveRights = computedEACL->EACL.entry[0].rights;
}
else
{
*effectiveRights = 0;
}
}
else
{
/*
* Compute rights in the normal case
*/
for (connectIndex = 0; connectIndex < numIDs; connectIndex++)
{ /* for each entry in the connection structure */
for (index = 0; index < numEntries;
index++)
{ /* for each entry in the effective ACL */
compare = LB_GUIDCompare(
&computedEACL->EACL.entry[index].trusteeID,
&IDs[connectIndex]);
if (compare == 0)
{
/* FixFixFix6 -- not checking for negative rights */
*effectiveRights |=
computedEACL->EACL.entry[index].rights;
break;
}
else if (compare > 0)
{ /* already past possible match */
break;
}
}
}
}
}
if (*effectiveRights & zAUTHORIZE_SUPERVISOR)
{
*effectiveRights |= zVALID_TRUSTEE_RIGHTS;
}
if (computedEACL && freeEACL)
{
free(computedEACL);
}
RTN_STATUS(zOK);
error:
RTN_STATUS(zFAILURE);
}
/*===========================================================================
*===========================================================================
*===========================================================================
*
* ZAS ACL OVERFLOW BEAST
*
*===========================================================================
*===========================================================================
*===========================================================================*/
/***************************************************************************
* This routine is called when an overflow beast is allocated in memory
***************************************************************************/
STATUS ACLO_ConstructBeast(
GeneralMsg_s *genMsg,
void *overflowBeast_LX)
{
ZasAclOverflowBeast_s *overflowBeast =
(ZasAclOverflowBeast_s *) overflowBeast_LX;
ASSERT_MPKNSS_LOCK();
ENTER(TAUTH, ACLO_ConstructBeast);
overflowBeast->acl = malloc(OVERFLOW_ALLOC_UNIT * sizeof(ACLEntry_s));
if (overflowBeast->acl == NULL)
{
SetErrno(genMsg, zERR_NO_MEMORY);
RTN_STATUS(zFAILURE);
}
overflowBeast->numAlloced = OVERFLOW_ALLOC_UNIT;
overflowBeast->p.nextOverflowZid = zINVALID_ZID;
overflowBeast->p.numEntries = 0;
RTN_STATUS(zOK);
}
/***************************************************************************
* This routine is called when an overflow beast is freed from memory
***************************************************************************/
void ACLO_DestructBeast(
void *overflowBeast_LX)
{
ZasAclOverflowBeast_s *overflowBeast =
(ZasAclOverflowBeast_s *) overflowBeast_LX;
ASSERT_MPKNSS_LOCK();
ENTER(TAUTH, ACLO_DestructBeast);
if (overflowBeast->acl != NULL)
{
free(overflowBeast->acl);
}
RTN_VOID();
}
/****************************************************************************
* ZAS OVERFLOW BEAST COMMON OPERATIONS definition
*****************************************************************************/
CommonBeastOps_s ACLO_ComnBeastOps =
{
ACLO_ConstructBeast, /* construct */
ACLO_DestructBeast, /* destruct */
// cnt NULL, /* BST_getNameUniquifier */
NULL, /* BST_setupNameTypeSpecificInfo */
NULL, /* BST_lookupByNameInDirectory*/
NULL, /* BST_isDirectoryEmpty*/
NULL, /* BST_addNameToDirectory*/
NULL, /* BST_removeNameFromDirectory*/
NULL, /* BST_modifyNameSpaceMaskInDirectory*/
NULL, /* BST_setMatchAttributesInDirectory*/
NULL, /* BST_wildcardLookup*/
NULL, /* BST_truncateFile*/
NULL, /* BST_getStorageInfo*/
NULL, /* BST_getExtentList*/
NULL, /* BST_getPhysicalExtent*/
NULL, /* BST_isBlockInBeast*/
NULL, /* BST_asyncReadFileBlk*/
NULL, /* BST_getFileBlk*/
NULL, /* BST_dfsReadUnits*/
NULL, /* BST_dfsWriteUnits*/
NULL, /* BST_getZID*/
NULL, /* BST_beastNotify*/
NULL, /* BST_getInfo*/
NULL, /* BST_modifyInfo*/
NULL, /* BST_getInfoXML*/
NULL /* BST_modifyInfoXML*/
};
///***************************************************************************
// * This routine is called when an overflow beast is written to storage
// ***************************************************************************/
//NINT ACLO_PackedSize(
// ZasAclOverflowBeast_s *overflowBeast)
//{
// ENTER(TAUTH, ACLO_PackedSize);
// RTN_NINT (sizeof(PersistentZasAclOverflowBeast_s) +
// (overflowBeast->p.numEntries * sizeof(ACLEntry_s)));
//}
//
///***************************************************************************
// * This routine is called when an overflow beast is written to storage
// ***************************************************************************/
//BYTE *ACLO_PackBeast(
// ZasAclOverflowBeast_s *overflowBeast,
// BYTE *storeBuffer)
//{
// NINT len;
//
// ENTER(TAUTH, ACLO_PackBeast);
// len = overflowBeast->p.numEntries * sizeof(ACLEntry_s);
// memcpy(storeBuffer, &overflowBeast->p, sizeof(PersistentZasAclOverflowBeast_s));
// storeBuffer += sizeof(PersistentZasAclOverflowBeast_s);
// zASSERT(overflowBeast->acl != NULL);
// memcpy(storeBuffer, overflowBeast->acl, len);
// RTN_PTR(storeBuffer + len);
//}
//
///***************************************************************************
// * This routine is called when an overflow beast is read from storage
// ***************************************************************************/
//BYTE *ACLO_UnpackBeast(
// GeneralMsg_s *genMsg,
// ZasAclOverflowBeast_s *overflowBeast,
// BYTE *storeBuffer)
//{
// NINT len;
//
// ENTER(TAUTH, ACLO_UnpackBeast);
// memcpy(&overflowBeast->p, storeBuffer, sizeof(PersistentZasAclOverflowBeast_s));
// storeBuffer += sizeof(PersistentZasAclOverflowBeast_s);
// len = overflowBeast->p.numEntries * sizeof(ACLEntry_s);
// zASSERT(len != 0);
// overflowBeast->acl = realloc(overflowBeast->acl, len);
// overflowBeast->numAlloced = overflowBeast->p.numEntries;
// if (overflowBeast->acl == NULL)
// {
// SetErrno(genMsg, zERR_NO_MEMORY);
// RTN_PTR(NULL);
// }
// memcpy(overflowBeast->acl, storeBuffer, len);
// RTN_PTR(storeBuffer + len);
//}
//
///*---------------------------------------------------------------------------
// * beast STORAGE ops definition
// *---------------------------------------------------------------------------*/
//StoragePoolBeastOps_s ACLO_StoragePoolOps[] =
//{
// {zFTYPE_ZFS_POOL, ACLO_PackedSize, ACLO_PackBeast, ACLO_UnpackBeast},
// /*{zFTYPE_ZFS_MEMPOOL, ACLO_PackedSize, ACLO_PackBeast, ACLO_UnpackBeast},*/
// {zFTYPE_INVALID}
//};
/*===========================================================================
*===========================================================================
*===========================================================================
*
* ZAS VISIBILITY OVERFLOW BEAST
*
*===========================================================================
*===========================================================================
*===========================================================================*/
/***************************************************************************
* This routine is called when an overflow beast is allocated in memory
***************************************************************************/
STATUS VISO_ConstructBeast(
GeneralMsg_s *genMsg,
void *overflowBeast_LX)
{
ZasVisOverflowBeast_s *overflowBeast =
(ZasVisOverflowBeast_s *) overflowBeast_LX;
ASSERT_MPKNSS_LOCK();
ENTER(TAUTH, VISO_ConstructBeast);
overflowBeast->vis = malloc(OVERFLOW_ALLOC_UNIT * sizeof(VisEntry_s));
if (overflowBeast->vis == NULL)
{
SetErrno(genMsg, zERR_NO_MEMORY);
RTN_STATUS(zFAILURE);
}
overflowBeast->numAlloced = OVERFLOW_ALLOC_UNIT;
overflowBeast->p.nextOverflowZid = zINVALID_ZID;
overflowBeast->p.numEntries = 0;
RTN_STATUS(zOK);
}
/***************************************************************************
* This routine is called when an overflow beast is freed from memory
***************************************************************************/
void VISO_DestructBeast(
void *overflowBeast_LX)
{
ZasVisOverflowBeast_s *overflowBeast =
(ZasVisOverflowBeast_s *) overflowBeast_LX;
ASSERT_MPKNSS_LOCK();
ENTER(TAUTH, VISO_DestructBeast);
if (overflowBeast->vis != NULL)
{
free(overflowBeast->vis);
}
RTN_VOID();
}
/****************************************************************************
* ZAS OVERFLOW BEAST COMMON OPERATIONS definition
*****************************************************************************/
CommonBeastOps_s VISO_ComnBeastOps =
{
VISO_ConstructBeast, /* construct */
VISO_DestructBeast, /* destruct */
// cnt NULL, /* BST_getNameUniquifier */
NULL, /* BST_setupNameTypeSpecificInfo */
NULL, /* BST_lookupByNameInDirectory*/
NULL, /* BST_isDirectoryEmpty*/
NULL, /* BST_addNameToDirectory*/
NULL, /* BST_removeNameFromDirectory*/
NULL, /* BST_modifyNameSpaceMaskInDirectory*/
NULL, /* BST_setMatchAttributesInDirectory*/
NULL, /* BST_wildcardLookup*/
NULL, /* BST_truncateFile*/
NULL, /* BST_getStorageInfo*/
NULL, /* BST_getExtentList*/
NULL, /* BST_isBlockInBeast*/
NULL, /* BST_asyncReadFileBlk*/
NULL, /* BST_getFileBlk*/
NULL, /* BST_dfsReadUnits*/
NULL, /* BST_dfsWriteUnits*/
NULL, /* BST_getZID*/
NULL, /* BST_beastNotify*/
NULL, /* BST_getInfo*/
NULL, /* BST_getInfoXML*/
NULL, /* BST_modifyInfo*/
NULL /* BST_modifyInfoXML*/
};
///***************************************************************************
// * This routine is called when an overflow beast is written to storage
// ***************************************************************************/
//NINT VISO_PackedSize(
// ZasVisOverflowBeast_s *overflowBeast)
//{
// ENTER(TAUTH, VISO_PackedSize);
// RTN_NINT(sizeof(PersistentZasVisOverflowBeast_s) +
// (overflowBeast->p.numEntries * sizeof(VisEntry_s)));
//}
//
///***************************************************************************
// * This routine is called when an overflow beast is written to storage
// ***************************************************************************/
//BYTE *VISO_PackBeast(
// ZasVisOverflowBeast_s *overflowBeast,
// BYTE *storeBuffer)
//{
// NINT len;
//
// ENTER(TAUTH, VISO_PackBeast);
// len = overflowBeast->p.numEntries * sizeof(VisEntry_s);
// memcpy(storeBuffer, &overflowBeast->p, sizeof(PersistentZasVisOverflowBeast_s));
// storeBuffer += sizeof(PersistentZasVisOverflowBeast_s);
// zASSERT(overflowBeast->vis != NULL);
// memcpy(storeBuffer, overflowBeast->vis, len);
// RTN_PTR(storeBuffer + len);
//}
//
///***************************************************************************
// * This routine is called when an overflow beast is read from storage
// ***************************************************************************/
//BYTE *VISO_UnpackBeast(
// GeneralMsg_s *genMsg,
// ZasVisOverflowBeast_s *overflowBeast,
// BYTE *storeBuffer)
//{
// NINT len;
//
// ENTER(TAUTH, VISO_UnpackBeast);
// memcpy(&overflowBeast->p, storeBuffer, sizeof(PersistentZasVisOverflowBeast_s));
// storeBuffer += sizeof(PersistentZasVisOverflowBeast_s);
// len = overflowBeast->p.numEntries * sizeof(VisEntry_s);
// overflowBeast->vis = realloc(overflowBeast->vis, len);
// overflowBeast->numAlloced = overflowBeast->p.numEntries;
// if (overflowBeast->vis == NULL)
// {
// SetErrno(genMsg, zERR_NO_MEMORY);
// RTN_PTR(NULL);
// }
// memcpy(overflowBeast->vis, storeBuffer, len);
// RTN_PTR(storeBuffer + len);
//}
//
///*---------------------------------------------------------------------------
// * beast STORAGE ops definition
// *---------------------------------------------------------------------------*/
//StoragePoolBeastOps_s VISO_StoragePoolOps[] =
//{
// {zFTYPE_ZFS_POOL, VISO_PackedSize, VISO_PackBeast, VISO_UnpackBeast},
// /*{zFTYPE_ZFS_MEMPOOL, VISO_PackedSize, VISO_PackBeast, VISO_UnpackBeast},*/
// {zFTYPE_INVALID}
//};