Files
SingularityViewer/indra/llinventory/llpermissions.cpp
2016-01-17 23:33:21 -05:00

1218 lines
29 KiB
C++

/**
* @file llpermissions.cpp
* @author Phoenix
* @brief Permissions for objects and inventory.
*
* $LicenseInfo:firstyear=2002&license=viewerlgpl$
* Second Life Viewer Source Code
* Copyright (C) 2010, Linden Research, Inc.
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation;
* version 2.1 of the License only.
*
* This library 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
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*
* Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA
* $/LicenseInfo$
*/
#include "linden_common.h"
#include "llpermissions.h"
// library includes
#include "message.h"
#include "llsd.h"
///----------------------------------------------------------------------------
/// Class LLPermissions
///----------------------------------------------------------------------------
const LLPermissions LLPermissions::DEFAULT;
// No creator = created by system
LLPermissions::LLPermissions()
{
init(LLUUID::null, LLUUID::null, LLUUID::null, LLUUID::null);
}
// Default to created by system
void LLPermissions::init(const LLUUID& creator, const LLUUID& owner, const LLUUID& last_owner, const LLUUID& group)
{
mCreator = creator;
mOwner = owner;
mLastOwner = last_owner;
mGroup = group;
mMaskBase = PERM_ALL;
mMaskOwner = PERM_ALL;
mMaskEveryone = PERM_ALL;
mMaskGroup = PERM_ALL;
mMaskNextOwner = PERM_ALL;
fixOwnership();
}
void LLPermissions::initMasks(PermissionMask base, PermissionMask owner,
PermissionMask everyone, PermissionMask group,
PermissionMask next)
{
mMaskBase = base;
mMaskOwner = owner;
mMaskEveryone = everyone;
mMaskGroup = group;
mMaskNextOwner = next;
fixFairUse();
fix();
}
// ! BACKWARDS COMPATIBILITY ! Override masks for inventory types that
// no longer can have restricted permissions. This takes care of previous
// version landmarks that could have had no copy/mod/transfer bits set.
void LLPermissions::initMasks(LLInventoryType::EType type)
{
if (LLInventoryType::cannotRestrictPermissions(type))
{
initMasks(PERM_ALL, PERM_ALL, PERM_ALL, PERM_ALL, PERM_ALL);
}
}
BOOL LLPermissions::getOwnership(LLUUID& owner_id, BOOL& is_group_owned) const
{
if(mOwner.notNull())
{
owner_id = mOwner;
is_group_owned = FALSE;
return TRUE;
}
else if(mIsGroupOwned)
{
owner_id = mGroup;
is_group_owned = TRUE;
return TRUE;
}
return FALSE;
}
LLUUID LLPermissions::getSafeOwner() const
{
if(mOwner.notNull())
{
return mOwner;
}
else if(mIsGroupOwned)
{
return mGroup;
}
else
{
LL_WARNS() << "LLPermissions::getSafeOwner() called with no valid owner!" << LL_ENDL;
LLUUID unused_uuid;
unused_uuid.generate();
return unused_uuid;
}
}
U32 LLPermissions::getCRC32() const
{
U32 rv = mCreator.getCRC32();
rv += mOwner.getCRC32();
rv += mLastOwner.getCRC32();
rv += mGroup.getCRC32();
rv += mMaskBase + mMaskOwner + mMaskEveryone + mMaskGroup;
return rv;
}
void LLPermissions::set(const LLPermissions& from)
{
mCreator = from.mCreator;
mOwner = from.mOwner;
mLastOwner = from.mLastOwner;
mGroup = from.mGroup;
mMaskBase = from.mMaskBase;
mMaskOwner = from.mMaskOwner;
mMaskEveryone = from.mMaskEveryone;
mMaskGroup = from.mMaskGroup;
mMaskNextOwner = from.mMaskNextOwner;
mIsGroupOwned = from.mIsGroupOwned;
}
// Fix hierarchy of permissions.
void LLPermissions::fix()
{
mMaskOwner &= mMaskBase;
mMaskGroup &= mMaskOwner;
// next owner uses base, since you may want to sell locked objects.
mMaskNextOwner &= mMaskBase;
mMaskEveryone &= mMaskOwner;
mMaskEveryone &= ~PERM_MODIFY;
if(!(mMaskBase & PERM_TRANSFER) && !mIsGroupOwned)
{
mMaskGroup &= ~PERM_COPY;
mMaskEveryone &= ~PERM_COPY;
// Do not set mask next owner to too restrictive because if we
// rez an object, it may require an ownership transfer during
// rez, which will note the overly restrictive perms, and then
// fix them to allow fair use, which may be different than the
// original intention.
}
}
// Correct for fair use - you can never take away the right to move
// stuff you own, and you can never take away the right to transfer
// something you cannot otherwise copy.
void LLPermissions::fixFairUse()
{
mMaskBase |= PERM_MOVE;
if(!(mMaskBase & PERM_COPY))
{
mMaskBase |= PERM_TRANSFER;
}
// (mask next owner == PERM_NONE) iff mask base is no transfer
if(mMaskNextOwner != PERM_NONE)
{
mMaskNextOwner |= PERM_MOVE;
}
}
void LLPermissions::fixOwnership()
{
if(mOwner.isNull() && mGroup.notNull())
{
mIsGroupOwned = true;
}
else
{
mIsGroupOwned = false;
}
}
// Allow accumulation of permissions. Results in the tightest
// permissions possible. In the case of clashing UUIDs, it sets the ID
// to LLUUID::null.
void LLPermissions::accumulate(const LLPermissions& perm)
{
if(perm.mCreator != mCreator)
{
mCreator = LLUUID::null;
}
if(perm.mOwner != mOwner)
{
mOwner = LLUUID::null;
}
if(perm.mLastOwner != mLastOwner)
{
mLastOwner = LLUUID::null;
}
if(perm.mGroup != mGroup)
{
mGroup = LLUUID::null;
}
mMaskBase &= perm.mMaskBase;
mMaskOwner &= perm.mMaskOwner;
mMaskGroup &= perm.mMaskGroup;
mMaskEveryone &= perm.mMaskEveryone;
mMaskNextOwner &= perm.mMaskNextOwner;
fix();
}
// saves last owner, sets current owner, and sets the group. note
// that this function has to more cleverly apply the fair use
// permissions.
BOOL LLPermissions::setOwnerAndGroup(
const LLUUID& agent,
const LLUUID& owner,
const LLUUID& group,
bool is_atomic)
{
BOOL allowed = FALSE;
if( agent.isNull() || mOwner.isNull()
|| ((agent == mOwner) && ((owner == mOwner) || (mMaskOwner & PERM_TRANSFER)) ) )
{
// ...system can alway set owner
// ...public objects can be claimed by anyone
// ...otherwise, agent must own it and have transfer ability
allowed = TRUE;
}
if (allowed)
{
if(mLastOwner.isNull() || (!mOwner.isNull() && (owner != mLastOwner)))
{
mLastOwner = mOwner;
}
if((mOwner != owner)
|| (mOwner.isNull() && owner.isNull() && (mGroup != group)))
{
mMaskBase = mMaskNextOwner;
mOwner = owner;
// this is a selective use of fair use for atomic
// permissions.
if(is_atomic && !(mMaskBase & PERM_COPY))
{
mMaskBase |= PERM_TRANSFER;
}
}
mGroup = group;
fixOwnership();
// if it's not atomic and we fix fair use, it blows away
//objects as inventory items which have different permissions
//than it's contents. :(
// fixFairUse();
mMaskBase |= PERM_MOVE;
if(mMaskNextOwner != PERM_NONE) mMaskNextOwner |= PERM_MOVE;
fix();
}
return allowed;
}
//Fix for DEV-33917, last owner isn't used much and has little impact on
//permissions so it's reasonably safe to do this, however, for now,
//limiting the functionality of this routine to objects which are
//group owned.
void LLPermissions::setLastOwner(const LLUUID& last_owner)
{
if (isGroupOwned())
mLastOwner = last_owner;
}
// only call this if you know what you're doing
// there are usually perm-bit consequences when the
// ownerhsip changes
void LLPermissions::yesReallySetOwner(const LLUUID& owner, bool group_owned)
{
mOwner = owner;
mIsGroupOwned = group_owned;
}
BOOL LLPermissions::deedToGroup(const LLUUID& agent, const LLUUID& group)
{
if(group.notNull() && (agent.isNull() || ((group == mGroup)
&& (mMaskOwner & PERM_TRANSFER)
&& (mMaskGroup & PERM_MOVE))))
{
if(mOwner.notNull())
{
mLastOwner = mOwner;
mOwner.setNull();
}
mMaskBase = mMaskNextOwner;
mMaskGroup = PERM_NONE;
mGroup = group;
mIsGroupOwned = true;
fixFairUse();
fix();
return TRUE;
}
return FALSE;
}
BOOL LLPermissions::setBaseBits(const LLUUID& agent, BOOL set, PermissionMask bits)
{
BOOL ownership = FALSE;
if(agent.isNull())
{
// only the system is always allowed to change base bits
ownership = TRUE;
}
if (ownership)
{
if (set)
{
mMaskBase |= bits; // turn on bits
}
else
{
mMaskBase &= ~bits; // turn off bits
}
fix();
}
return ownership;
}
// Note: If you attempt to set bits that the base bits doesn't allow,
// the function will succeed, but those bits will not be set.
BOOL LLPermissions::setOwnerBits(const LLUUID& agent, BOOL set, PermissionMask bits)
{
BOOL ownership = FALSE;
if(agent.isNull())
{
// ...system always allowed to change things
ownership = TRUE;
}
else if (agent == mOwner)
{
// ...owner bits can only be set by owner
ownership = TRUE;
}
// If we have correct ownership and
if (ownership)
{
if (set)
{
mMaskOwner |= bits; // turn on bits
}
else
{
mMaskOwner &= ~bits; // turn off bits
}
fix();
}
return (ownership);
}
BOOL LLPermissions::setGroupBits(const LLUUID& agent, const LLUUID& group, BOOL set, PermissionMask bits)
{
BOOL ownership = FALSE;
if((agent.isNull()) || (agent == mOwner)
|| ((group == mGroup) && (!mGroup.isNull())))
{
// The group bits can be set by the system, the owner, or a
// group member.
ownership = TRUE;
}
if (ownership)
{
if (set)
{
mMaskGroup |= bits;
}
else
{
mMaskGroup &= ~bits;
}
fix();
}
return ownership;
}
// Note: If you attempt to set bits that the creator or owner doesn't allow,
// the function will succeed, but those bits will not be set.
BOOL LLPermissions::setEveryoneBits(const LLUUID& agent, const LLUUID& group, BOOL set, PermissionMask bits)
{
BOOL ownership = FALSE;
if((agent.isNull()) || (agent == mOwner)
|| ((group == mGroup) && (!mGroup.isNull())))
{
// The everyone bits can be set by the system, the owner, or a
// group member.
ownership = TRUE;
}
if (ownership)
{
if (set)
{
mMaskEveryone |= bits;
}
else
{
mMaskEveryone &= ~bits;
}
// Fix hierarchy of permissions
fix();
}
return ownership;
}
// Note: If you attempt to set bits that the creator or owner doesn't allow,
// the function will succeed, but those bits will not be set.
BOOL LLPermissions::setNextOwnerBits(const LLUUID& agent, const LLUUID& group, BOOL set, PermissionMask bits)
{
BOOL ownership = FALSE;
if((agent.isNull()) || (agent == mOwner)
|| ((group == mGroup) && (!mGroup.isNull())))
{
// The next owner bits can be set by the system, the owner, or
// a group member.
ownership = TRUE;
}
if (ownership)
{
if (set)
{
mMaskNextOwner |= bits;
}
else
{
mMaskNextOwner &= ~bits;
}
// Fix-up permissions
if(!(mMaskNextOwner & PERM_COPY))
{
mMaskNextOwner |= PERM_TRANSFER;
}
fix();
}
return ownership;
}
bool LLPermissions::allowOperationBy(PermissionBit op, const LLUUID& requester, const LLUUID& group) const
{
if(requester.isNull())
{
// ...system making request
// ...not owned
return TRUE;
}
else if (mIsGroupOwned && (mGroup == requester))
{
// group checking ownership permissions
return (mMaskOwner & op);
}
else if (!mIsGroupOwned && (mOwner == requester))
{
// ...owner making request
return (mMaskOwner & op);
}
else if(mGroup.notNull() && (mGroup == group))
{
// group member making request
return ((mMaskGroup & op) || (mMaskEveryone & op));
}
return (mMaskEveryone & op);
}
//
// LLSD support for HTTP messages.
//
LLSD LLPermissions::packMessage() const
{
LLSD result;
result["creator-id"] = mCreator;
result["owner-id"] = mOwner;
result["group-id"] = mGroup;
result["base-mask"] = (S32)mMaskBase;
result["owner-mask"] = (S32)mMaskOwner;
result["group-mask"] = (S32)mMaskGroup;
result["everyone-mask"] = (S32)mMaskEveryone;
result["next-owner-mask"]= (S32)mMaskNextOwner;
result["group-owned"] = (BOOL)mIsGroupOwned;
return result;
}
//
// Messaging support
//
void LLPermissions::packMessage(LLMessageSystem* msg) const
{
msg->addUUIDFast(_PREHASH_CreatorID, mCreator);
msg->addUUIDFast(_PREHASH_OwnerID, mOwner);
msg->addUUIDFast(_PREHASH_GroupID, mGroup);
msg->addU32Fast(_PREHASH_BaseMask, mMaskBase );
msg->addU32Fast(_PREHASH_OwnerMask, mMaskOwner );
msg->addU32Fast(_PREHASH_GroupMask, mMaskGroup );
msg->addU32Fast(_PREHASH_EveryoneMask, mMaskEveryone );
msg->addU32Fast(_PREHASH_NextOwnerMask, mMaskNextOwner );
msg->addBOOLFast(_PREHASH_GroupOwned, (BOOL)mIsGroupOwned);
}
void LLPermissions::unpackMessage(const LLSD& perms)
{
mCreator = perms["creator-id"];
mOwner = perms["owner-id"];
mGroup = perms["group-id"];
mMaskBase = (U32)perms["base-mask"].asInteger();
mMaskOwner = (U32)perms["owner-mask"].asInteger();
mMaskGroup = (U32)perms["group-mask"].asInteger();
mMaskEveryone = (U32)perms["everyone-mask"].asInteger();
mMaskNextOwner = (U32)perms["next-owner-mask"].asInteger();
mIsGroupOwned = perms["group-owned"].asBoolean();
}
void LLPermissions::unpackMessage(LLMessageSystem* msg, const char* block, S32 block_num)
{
msg->getUUIDFast(block, _PREHASH_CreatorID, mCreator, block_num);
msg->getUUIDFast(block, _PREHASH_OwnerID, mOwner, block_num);
msg->getUUIDFast(block, _PREHASH_GroupID, mGroup, block_num);
msg->getU32Fast(block, _PREHASH_BaseMask, mMaskBase, block_num );
msg->getU32Fast(block, _PREHASH_OwnerMask, mMaskOwner, block_num );
msg->getU32Fast(block, _PREHASH_GroupMask, mMaskGroup, block_num );
msg->getU32Fast(block, _PREHASH_EveryoneMask, mMaskEveryone, block_num );
msg->getU32Fast(block, _PREHASH_NextOwnerMask, mMaskNextOwner, block_num );
BOOL tmp;
msg->getBOOLFast(block, _PREHASH_GroupOwned, tmp, block_num);
mIsGroupOwned = (bool)tmp;
}
//
// File support
//
BOOL LLPermissions::importFile(LLFILE* fp)
{
init(LLUUID::null, LLUUID::null, LLUUID::null, LLUUID::null);
const S32 BUFSIZE = 16384;
// *NOTE: Changing the buffer size will require changing the scanf
// calls below.
char buffer[BUFSIZE]; /* Flawfinder: ignore */
char keyword[256]; /* Flawfinder: ignore */
char valuestr[256]; /* Flawfinder: ignore */
char uuid_str[256]; /* Flawfinder: ignore */
U32 mask;
keyword[0] = '\0';
valuestr[0] = '\0';
while (!feof(fp))
{
if (fgets(buffer, BUFSIZE, fp) == NULL)
{
buffer[0] = '\0';
}
sscanf( /* Flawfinder: ignore */
buffer,
" %255s %255s",
keyword, valuestr);
if (!strcmp("{", keyword))
{
continue;
}
if (!strcmp("}",keyword))
{
break;
}
else if (!strcmp("creator_mask", keyword))
{
// legacy support for "creator" masks
sscanf(valuestr, "%x", &mask);
mMaskBase = mask;
fixFairUse();
}
else if (!strcmp("base_mask", keyword))
{
sscanf(valuestr, "%x", &mask);
mMaskBase = mask;
//fixFairUse();
}
else if (!strcmp("owner_mask", keyword))
{
sscanf(valuestr, "%x", &mask);
mMaskOwner = mask;
}
else if (!strcmp("group_mask", keyword))
{
sscanf(valuestr, "%x", &mask);
mMaskGroup = mask;
}
else if (!strcmp("everyone_mask", keyword))
{
sscanf(valuestr, "%x", &mask);
mMaskEveryone = mask;
}
else if (!strcmp("next_owner_mask", keyword))
{
sscanf(valuestr, "%x", &mask);
mMaskNextOwner = mask;
}
else if (!strcmp("creator_id", keyword))
{
sscanf(valuestr, "%255s", uuid_str); /* Flawfinder: ignore */
mCreator.set(uuid_str);
}
else if (!strcmp("owner_id", keyword))
{
sscanf(valuestr, "%255s", uuid_str); /* Flawfinder: ignore */
mOwner.set(uuid_str);
}
else if (!strcmp("last_owner_id", keyword))
{
sscanf(valuestr, "%255s", uuid_str); /* Flawfinder: ignore */
mLastOwner.set(uuid_str);
}
else if (!strcmp("group_id", keyword))
{
sscanf(valuestr, "%255s", uuid_str); /* Flawfinder: ignore */
mGroup.set(uuid_str);
}
else if (!strcmp("group_owned", keyword))
{
sscanf(valuestr, "%d", &mask);
if(mask) mIsGroupOwned = true;
else mIsGroupOwned = false;
}
else
{
LL_INFOS() << "unknown keyword " << keyword << " in permissions import" << LL_ENDL;
}
}
fix();
return TRUE;
}
BOOL LLPermissions::exportFile(LLFILE* fp) const
{
std::string uuid_str;
fprintf(fp, "\tpermissions 0\n");
fprintf(fp, "\t{\n");
fprintf(fp, "\t\tbase_mask\t%08x\n", mMaskBase);
fprintf(fp, "\t\towner_mask\t%08x\n", mMaskOwner);
fprintf(fp, "\t\tgroup_mask\t%08x\n", mMaskGroup);
fprintf(fp, "\t\teveryone_mask\t%08x\n", mMaskEveryone);
fprintf(fp, "\t\tnext_owner_mask\t%08x\n", mMaskNextOwner);
mCreator.toString(uuid_str);
fprintf(fp, "\t\tcreator_id\t%s\n", uuid_str.c_str());
mOwner.toString(uuid_str);
fprintf(fp, "\t\towner_id\t%s\n", uuid_str.c_str());
mLastOwner.toString(uuid_str);
fprintf(fp, "\t\tlast_owner_id\t%s\n", uuid_str.c_str());
mGroup.toString(uuid_str);
fprintf(fp, "\t\tgroup_id\t%s\n", uuid_str.c_str());
if(mIsGroupOwned)
{
fprintf(fp, "\t\tgroup_owned\t1\n");
}
fprintf(fp,"\t}\n");
return TRUE;
}
BOOL LLPermissions::importLegacyStream(std::istream& input_stream)
{
init(LLUUID::null, LLUUID::null, LLUUID::null, LLUUID::null);
const S32 BUFSIZE = 16384;
// *NOTE: Changing the buffer size will require changing the scanf
// calls below.
char buffer[BUFSIZE]; /* Flawfinder: ignore */
char keyword[256]; /* Flawfinder: ignore */
char valuestr[256]; /* Flawfinder: ignore */
char uuid_str[256]; /* Flawfinder: ignore */
U32 mask;
keyword[0] = '\0';
valuestr[0] = '\0';
while (input_stream.good())
{
input_stream.getline(buffer, BUFSIZE);
sscanf( /* Flawfinder: ignore */
buffer,
" %255s %255s",
keyword, valuestr);
if (!strcmp("{", keyword))
{
continue;
}
if (!strcmp("}",keyword))
{
break;
}
else if (!strcmp("creator_mask", keyword))
{
// legacy support for "creator" masks
sscanf(valuestr, "%x", &mask);
mMaskBase = mask;
fixFairUse();
}
else if (!strcmp("base_mask", keyword))
{
sscanf(valuestr, "%x", &mask);
mMaskBase = mask;
//fixFairUse();
}
else if (!strcmp("owner_mask", keyword))
{
sscanf(valuestr, "%x", &mask);
mMaskOwner = mask;
}
else if (!strcmp("group_mask", keyword))
{
sscanf(valuestr, "%x", &mask);
mMaskGroup = mask;
}
else if (!strcmp("everyone_mask", keyword))
{
sscanf(valuestr, "%x", &mask);
mMaskEveryone = mask;
}
else if (!strcmp("next_owner_mask", keyword))
{
sscanf(valuestr, "%x", &mask);
mMaskNextOwner = mask;
}
else if (!strcmp("creator_id", keyword))
{
sscanf(valuestr, "%255s", uuid_str); /* Flawfinder: ignore */
mCreator.set(uuid_str);
}
else if (!strcmp("owner_id", keyword))
{
sscanf(valuestr, "%255s", uuid_str); /* Flawfinder: ignore */
mOwner.set(uuid_str);
}
else if (!strcmp("last_owner_id", keyword))
{
sscanf(valuestr, "%255s", uuid_str); /* Flawfinder: ignore */
mLastOwner.set(uuid_str);
}
else if (!strcmp("group_id", keyword))
{
sscanf(valuestr, "%255s", uuid_str); /* Flawfinder: ignore */
mGroup.set(uuid_str);
}
else if (!strcmp("group_owned", keyword))
{
sscanf(valuestr, "%d", &mask);
if(mask) mIsGroupOwned = true;
else mIsGroupOwned = false;
}
else
{
LL_WARNS() << "unknown keyword " << keyword
<< " in permissions import" << LL_ENDL;
}
}
fix();
return TRUE;
}
BOOL LLPermissions::exportLegacyStream(std::ostream& output_stream) const
{
std::string uuid_str;
output_stream << "\tpermissions 0\n";
output_stream << "\t{\n";
std::string buffer;
buffer = llformat( "\t\tbase_mask\t%08x\n", mMaskBase);
output_stream << buffer;
buffer = llformat( "\t\towner_mask\t%08x\n", mMaskOwner);
output_stream << buffer;
buffer = llformat( "\t\tgroup_mask\t%08x\n", mMaskGroup);
output_stream << buffer;
buffer = llformat( "\t\teveryone_mask\t%08x\n", mMaskEveryone);
output_stream << buffer;
buffer = llformat( "\t\tnext_owner_mask\t%08x\n", mMaskNextOwner);
output_stream << buffer;
mCreator.toString(uuid_str);
output_stream << "\t\tcreator_id\t" << uuid_str << "\n";
mOwner.toString(uuid_str);
output_stream << "\t\towner_id\t" << uuid_str << "\n";
mLastOwner.toString(uuid_str);
output_stream << "\t\tlast_owner_id\t" << uuid_str << "\n";
mGroup.toString(uuid_str);
output_stream << "\t\tgroup_id\t" << uuid_str << "\n";
if(mIsGroupOwned)
{
output_stream << "\t\tgroup_owned\t1\n";
}
output_stream << "\t}\n";
return TRUE;
}
// Deleted LLPermissions::exportFileXML() and LLPermissions::importXML()
// because I can't find any non-test code references to it. 2009-05-04 JC
bool LLPermissions::operator==(const LLPermissions &rhs) const
{
return
(mCreator == rhs.mCreator) &&
(mOwner == rhs.mOwner) &&
(mLastOwner == rhs.mLastOwner ) &&
(mGroup == rhs.mGroup ) &&
(mMaskBase == rhs.mMaskBase ) &&
(mMaskOwner == rhs.mMaskOwner ) &&
(mMaskGroup == rhs.mMaskGroup ) &&
(mMaskEveryone == rhs.mMaskEveryone ) &&
(mMaskNextOwner == rhs.mMaskNextOwner ) &&
(mIsGroupOwned == rhs.mIsGroupOwned);
}
bool LLPermissions::operator!=(const LLPermissions &rhs) const
{
return
(mCreator != rhs.mCreator) ||
(mOwner != rhs.mOwner) ||
(mLastOwner != rhs.mLastOwner ) ||
(mGroup != rhs.mGroup ) ||
(mMaskBase != rhs.mMaskBase ) ||
(mMaskOwner != rhs.mMaskOwner ) ||
(mMaskGroup != rhs.mMaskGroup ) ||
(mMaskEveryone != rhs.mMaskEveryone ) ||
(mMaskNextOwner != rhs.mMaskNextOwner) ||
(mIsGroupOwned != rhs.mIsGroupOwned);
}
std::ostream& operator<<(std::ostream &s, const LLPermissions &perm)
{
s << "{Creator=" << perm.getCreator();
s << ", Owner=" << perm.getOwner();
s << ", Group=" << perm.getGroup();
s << std::hex << ", BaseMask=0x" << perm.getMaskBase();
s << ", OwnerMask=0x" << perm.getMaskOwner();
s << ", EveryoneMask=0x" << perm.getMaskEveryone();
s << ", GroupMask=0x" << perm.getMaskGroup();
s << ", NextOwnerMask=0x" << perm.getMaskNextOwner() << std::dec;
s << "}";
return s;
}
///----------------------------------------------------------------------------
/// Class LLAggregatePermissions
///----------------------------------------------------------------------------
const LLAggregatePermissions LLAggregatePermissions::empty;
LLAggregatePermissions::LLAggregatePermissions()
{
for(S32 i = 0; i < PI_COUNT; ++i)
{
mBits[i] = AP_EMPTY;
}
}
LLAggregatePermissions::EValue LLAggregatePermissions::getValue(PermissionBit bit) const
{
EPermIndex idx = perm2PermIndex(bit);
EValue rv = AP_EMPTY;
if(idx != PI_END)
{
rv = (LLAggregatePermissions::EValue)(mBits[idx]);
}
return rv;
}
// returns the bits compressed into a single byte: 00TTMMCC
// where TT = transfer, MM = modify, and CC = copy
// LSB is to the right
U8 LLAggregatePermissions::getU8() const
{
U8 byte = mBits[PI_TRANSFER];
byte <<= 2;
byte |= mBits[PI_MODIFY];
byte <<= 2;
byte |= mBits[PI_COPY];
return byte;
}
BOOL LLAggregatePermissions::isEmpty() const
{
for(S32 i = 0; i < PI_END; ++i)
{
if(mBits[i] != AP_EMPTY)
{
return FALSE;
}
}
return TRUE;
}
void LLAggregatePermissions::aggregate(PermissionMask mask)
{
BOOL is_allowed = mask & PERM_COPY;
aggregateBit(PI_COPY, is_allowed);
is_allowed = mask & PERM_MODIFY;
aggregateBit(PI_MODIFY, is_allowed);
is_allowed = mask & PERM_TRANSFER;
aggregateBit(PI_TRANSFER, is_allowed);
}
void LLAggregatePermissions::aggregate(const LLAggregatePermissions& ag)
{
for(S32 idx = PI_COPY; idx != PI_END; ++idx)
{
aggregateIndex((EPermIndex)idx, ag.mBits[idx]);
}
}
void LLAggregatePermissions::aggregateBit(EPermIndex idx, BOOL allowed)
{
//if(AP_SOME == mBits[idx]) return; // P4 branch prediction optimization
switch(mBits[idx])
{
case AP_EMPTY:
mBits[idx] = allowed ? AP_ALL : AP_NONE;
break;
case AP_NONE:
mBits[idx] = allowed ? AP_SOME: AP_NONE;
break;
case AP_SOME:
// no-op
break;
case AP_ALL:
mBits[idx] = allowed ? AP_ALL : AP_SOME;
break;
default:
LL_WARNS() << "Bad aggregateBit " << (S32)idx << " "
<< (allowed ? "true" : "false") << LL_ENDL;
break;
}
}
void LLAggregatePermissions::aggregateIndex(EPermIndex idx, U8 bits)
{
switch(mBits[idx])
{
case AP_EMPTY:
mBits[idx] = bits;
break;
case AP_NONE:
switch(bits)
{
case AP_SOME:
case AP_ALL:
mBits[idx] = AP_SOME;
break;
case AP_EMPTY:
case AP_NONE:
default:
// no-op
break;
}
break;
case AP_SOME:
// no-op
break;
case AP_ALL:
switch(bits)
{
case AP_NONE:
case AP_SOME:
mBits[idx] = AP_SOME;
break;
case AP_EMPTY:
case AP_ALL:
default:
// no-op
break;
}
break;
default:
LL_WARNS() << "Bad aggregate index " << (S32)idx << " "
<< (S32)bits << LL_ENDL;
break;
}
}
// static
LLAggregatePermissions::EPermIndex LLAggregatePermissions::perm2PermIndex(PermissionBit bit)
{
EPermIndex idx = PI_END; // past any good value.
switch(bit)
{
case PERM_COPY:
idx = PI_COPY;
break;
case PERM_MODIFY:
idx = PI_MODIFY;
break;
case PERM_TRANSFER:
idx = PI_TRANSFER;
break;
default:
break;
}
return idx;
}
void LLAggregatePermissions::packMessage(LLMessageSystem* msg, const char* field) const
{
msg->addU8Fast(field, getU8());
}
void LLAggregatePermissions::unpackMessage(LLMessageSystem* msg, const char* block, const char* field, S32 block_num)
{
const U8 TWO_BITS = 0x3; // binary 00000011
U8 bits = 0;
msg->getU8Fast(block, field, bits, block_num);
mBits[PI_COPY] = bits & TWO_BITS;
bits >>= 2;
mBits[PI_MODIFY] = bits & TWO_BITS;
bits >>= 2;
mBits[PI_TRANSFER] = bits & TWO_BITS;
}
const std::string AGGREGATE_VALUES[4] =
{
std::string( "Empty" ),
std::string( "None" ),
std::string( "Some" ),
std::string( "All" )
};
std::ostream& operator<<(std::ostream &s, const LLAggregatePermissions &perm)
{
s << "{PI_COPY=" << AGGREGATE_VALUES[perm.mBits[LLAggregatePermissions::PI_COPY]];
s << ", PI_MODIFY=" << AGGREGATE_VALUES[perm.mBits[LLAggregatePermissions::PI_MODIFY]];
s << ", PI_TRANSFER=" << AGGREGATE_VALUES[perm.mBits[LLAggregatePermissions::PI_TRANSFER]];
s << "}";
return s;
}
// This converts a permissions mask into a string for debugging use.
void mask_to_string(U32 mask, char* str)
{
if (mask & PERM_MOVE)
{
*str = 'V';
}
else
{
*str = ' ';
}
str++;
if (mask & PERM_MODIFY)
{
*str = 'M';
}
else
{
*str = ' ';
}
str++;
if (mask & PERM_COPY)
{
*str = 'C';
}
else
{
*str = ' ';
}
str++;
if (mask & PERM_TRANSFER)
{
*str = 'T';
}
else
{
*str = ' ';
}
str++;
if (mask & PERM_EXPORT)
{
*str = 'E';
}
else
{
*str = ' ';
}
str++;
*str = '\0';
}
std::string mask_to_string(U32 mask)
{
char str[16];
mask_to_string(mask, str);
return std::string(str);
}
///----------------------------------------------------------------------------
/// exported functions
///----------------------------------------------------------------------------
static const std::string PERM_CREATOR_ID_LABEL("creator_id");
static const std::string PERM_OWNER_ID_LABEL("owner_id");
static const std::string PERM_LAST_OWNER_ID_LABEL("last_owner_id");
static const std::string PERM_GROUP_ID_LABEL("group_id");
static const std::string PERM_IS_OWNER_GROUP_LABEL("is_owner_group");
static const std::string PERM_BASE_MASK_LABEL("base_mask");
static const std::string PERM_OWNER_MASK_LABEL("owner_mask");
static const std::string PERM_GROUP_MASK_LABEL("group_mask");
static const std::string PERM_EVERYONE_MASK_LABEL("everyone_mask");
static const std::string PERM_NEXT_OWNER_MASK_LABEL("next_owner_mask");
LLSD ll_create_sd_from_permissions(const LLPermissions& perm)
{
LLSD rv;
rv[PERM_CREATOR_ID_LABEL] = perm.getCreator();
rv[PERM_OWNER_ID_LABEL] = perm.getOwner();
rv[PERM_LAST_OWNER_ID_LABEL] = perm.getLastOwner();
rv[PERM_GROUP_ID_LABEL] = perm.getGroup();
rv[PERM_IS_OWNER_GROUP_LABEL] = perm.isGroupOwned();
rv[PERM_BASE_MASK_LABEL] = (S32)perm.getMaskBase();
rv[PERM_OWNER_MASK_LABEL] = (S32)perm.getMaskOwner();
rv[PERM_GROUP_MASK_LABEL] = (S32)perm.getMaskGroup();
rv[PERM_EVERYONE_MASK_LABEL] = (S32)perm.getMaskEveryone();
rv[PERM_NEXT_OWNER_MASK_LABEL] = (S32)perm.getMaskNextOwner();
return rv;
}
LLPermissions ll_permissions_from_sd(const LLSD& sd_perm)
{
LLPermissions rv;
rv.init(
sd_perm[PERM_CREATOR_ID_LABEL].asUUID(),
sd_perm[PERM_OWNER_ID_LABEL].asUUID(),
sd_perm[PERM_LAST_OWNER_ID_LABEL].asUUID(),
sd_perm[PERM_GROUP_ID_LABEL].asUUID());
// We do a cast to U32 here since LLSD does not attempt to
// represent unsigned ints.
PermissionMask mask;
mask = (U32)(sd_perm[PERM_BASE_MASK_LABEL].asInteger());
rv.setMaskBase(mask);
mask = (U32)(sd_perm[PERM_OWNER_MASK_LABEL].asInteger());
rv.setMaskOwner(mask);
mask = (U32)(sd_perm[PERM_EVERYONE_MASK_LABEL].asInteger());
rv.setMaskEveryone(mask);
mask = (U32)(sd_perm[PERM_GROUP_MASK_LABEL].asInteger());
rv.setMaskGroup(mask);
mask = (U32)(sd_perm[PERM_NEXT_OWNER_MASK_LABEL].asInteger());
rv.setMaskNext(mask);
rv.fix();
return rv;
}
bool LLPermissions::allowExportBy(LLUUID const& requester, ExportPolicy export_policy) const
{
return !mIsGroupOwned && requester == mOwner && // Must be owner.
(requester == mCreator || // Export is allowed for all export policies when creator.
(export_policy == ep_export_bit && (mMaskEveryone & PERM_EXPORT)) || // If not creator, only allow export when PERM_EXPORT bit is set.
(export_policy == ep_full_perm && (mMaskOwner & PERM_ITEM_UNRESTRICTED) == PERM_ITEM_UNRESTRICTED)); // If not creator, only allow export when item is full perm.
}