blob: 513a2bda4298670c25649686b3aa682a3f2c3a40 [file] [log] [blame]
//*****************************************************************************
// @@@ START COPYRIGHT @@@
//
// Licensed to the Apache Software Foundation (ASF) under one
// or more contributor license agreements. See the NOTICE file
// distributed with this work for additional information
// regarding copyright ownership. The ASF licenses this file
// to you under the Apache License, Version 2.0 (the
// "License"); you may not use this file except in compliance
// with the License. You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing,
// software distributed under the License is distributed on an
// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
// KIND, either express or implied. See the License for the
// specific language governing permissions and limitations
// under the License.
//
// @@@ END COPYRIGHT @@@
//*****************************************************************************
#include "PrivMgrPrivileges.h"
#include "PrivMgrMD.h"
#include "PrivMgrMDTable.h"
#include "PrivMgrDesc.h"
#include "PrivMgrDefs.h"
#include "PrivMgrRoles.h"
#include "PrivMgrComponentPrivileges.h"
#include "PrivMgrObjects.h"
#include "PrivMgrCommands.h"
#include <numeric>
#include <cstdio>
#include <algorithm>
#include <iterator>
#include <vector>
#include "sqlcli.h"
#include "ComSmallDefs.h"
#include "ExExeUtilCli.h"
#include "ComDiags.h"
#include "ComQueue.h"
#include "CmpCommon.h"
#include "CmpContext.h"
#include "ComSecurityKey.h"
#include "NAUserId.h"
#include "ComUser.h"
#include "CmpSeabaseDDLutil.h"
#include "logmxevent_traf.h"
class ColPrivGrant;
class ColumnPrivsMDTable;
// ****************************************************************************
// File: PrivMgrPrivileges.h
//
// This file contains:
// class ObjectPrivsMDRow
// class ObjectPrivsMDTable
// non inline methods for class PrivMgrPrivileges
// ****************************************************************************
// *****************************************************************************
// * Class: ObjectPrivsMDRow
// * Description: This class represents a row from the OBJECT_PRIVILEGES table
// *
// * An object row can be uniquely identified by its object UID, granteeID
// * and grantorID.
// *****************************************************************************
class ObjectPrivsMDRow : public PrivMgrMDRow
{
public:
// -------------------------------------------------------------------
// Constructors and destructors:
// -------------------------------------------------------------------
ObjectPrivsMDRow()
: PrivMgrMDRow(PRIVMGR_OBJECT_PRIVILEGES, OBJECT_PRIVILEGES_ENUM),
objectUID_(0),
grantorID_(0),
granteeID_(0)
{ };
ObjectPrivsMDRow(const ObjectPrivsMDRow &other)
: PrivMgrMDRow(other)
{
objectUID_ = other.objectUID_;
objectName_ = other.objectName_;
objectType_ = other.objectType_;
granteeID_ = other.granteeID_;
granteeName_ = other.granteeName_;
granteeType_ = other.granteeType_;
grantorID_ = other.grantorID_;
grantorName_ = other.grantorName_;
grantorType_ = other.grantorType_;
privsBitmap_ = other.privsBitmap_;
grantableBitmap_ = other.grantableBitmap_;
current_ = other.current_;
visited_ = other.visited_;
};
virtual ~ObjectPrivsMDRow() {};
// Methods used to determine changes after processing revoked privileges
PrivMgrCoreDesc& accessCurrent() { return current_; }
PrivMgrCoreDesc& accessVisited() { return visited_; }
void clearVisited() { visited_.setAllPrivAndWgo(false); };
bool isChanged()
{ return (current_ == PrivMgrCoreDesc(privsBitmap_, grantableBitmap_)); }
void setToOriginal() { current_ = PrivMgrCoreDesc(privsBitmap_, grantableBitmap_); }
;
// Return True iff some current flag is set, where visited is not.
NABoolean anyNotVisited() const {return current_.anyNotSet( visited_ );}
// Clear current where current was set and visited was not.
// Return True iff some current flag gets cleared.
NABoolean cascadeLosses();
// Describe a row for tracing
void describeRow (std::string &rowDetails);
// -------------------------------------------------------------------
// Data Members:
// -------------------------------------------------------------------
int64_t objectUID_;
std::string objectName_;
ComObjectType objectType_;
int32_t granteeID_;
std::string granteeName_;
std::string granteeType_;
int32_t grantorID_;
std::string grantorName_;
std::string grantorType_;
PrivObjectBitmap privsBitmap_;
PrivObjectBitmap grantableBitmap_;
PrivMgrCoreDesc visited_;
PrivMgrCoreDesc current_;
};
// *****************************************************************************
// * Class: ObjectPrivsMDTable
// * Description: This class represents the OBJECT_PRIVILEGES table
// *
// * An object privileges row can be uniquely identified by:
// * objectUID
// * granteeID
// * grantorID
// *****************************************************************************
class ObjectPrivsMDTable : public PrivMgrMDTable
{
public:
ObjectPrivsMDTable(
const std::string & tableName,
ComDiagsArea * pDiags = NULL)
: PrivMgrMDTable(tableName,OBJECT_PRIVILEGES_ENUM, pDiags)
{};
virtual ~ObjectPrivsMDTable()
{};
virtual PrivStatus insert(const PrivMgrMDRow &row);
virtual PrivStatus selectWhereUnique(
const std::string & whereClause,
PrivMgrMDRow & row);
PrivStatus selectWhere(
const std::string & whereClause,
const std::string & orderByClause,
std::vector<PrivMgrMDRow *> &rowList);
PrivStatus deleteRow(const ObjectPrivsMDRow & row);
virtual PrivStatus deleteWhere(const std::string & whereClause);
PrivStatus updateRow(const ObjectPrivsMDRow & row);
PrivStatus updateWhere(
const std::string & setClause,
const std::string & whereClause);
PrivStatus insertSelect(
const std::string & objectsLocation,
const std::string & authsLocation);
PrivStatus insertSelectOnAuthsToPublic(
const std::string &objectsLocation,
const std::string &authsLocation);
private:
ObjectPrivsMDTable();
void setRow(OutputInfo *pCliRow, ObjectPrivsMDRow &rowOut);
};
// *****************************************************************************
// * Class: ColumnPrivsMDRow
// * Description: This class represents a row from the COLUMN_PRIVILEGES table
// *
// * An column row can be uniquely identified by its object UID, granteeID,
// * grantorID, and column ordinal.
// *****************************************************************************
class ColumnPrivsMDRow : public PrivMgrMDRow
{
public:
// -------------------------------------------------------------------
// Constructors and destructors:
// -------------------------------------------------------------------
ColumnPrivsMDRow()
: PrivMgrMDRow(PRIVMGR_COLUMN_PRIVILEGES, COLUMN_PRIVILEGES_ENUM),
objectUID_(0),
grantorID_(0),
granteeID_(0),
columnOrdinal_(0)
{ };
ColumnPrivsMDRow(const ColumnPrivsMDRow &other)
: PrivMgrMDRow(other)
{
objectUID_ = other.objectUID_;
objectName_ = other.objectName_;
granteeID_ = other.granteeID_;
granteeName_ = other.granteeName_;
grantorID_ = other.grantorID_;
grantorName_ = other.grantorName_;
columnOrdinal_ = other.columnOrdinal_;
privsBitmap_ = other.privsBitmap_;
grantableBitmap_ = other.grantableBitmap_;
};
virtual ~ColumnPrivsMDRow() {};
// Describe a row for tracing
void describeRow (std::string &rowDetails);
// sets the privilege and grantable bitmaps to 0
void clearVisited()
{
visited_.setColumnOrdinal(columnOrdinal_);
visited_.setAllPrivAndWgo(false);
}
// sets the current entry to match the original privileges
// before they are adjusted by a revoke command
void setCurrentToOriginal()
{
current_.setColumnOrdinal(columnOrdinal_);
current_.setPrivBitmap(privsBitmap_);
current_.setWgoBitmap(grantableBitmap_);
}
// compares the current privileges with the visited grant tree to
// see if there are any broken branches
NABoolean anyNotVisited()
{return current_.getPrivBitmap() != visited_.getPrivBitmap() ||
current_.getWgoBitmap() != visited_.getWgoBitmap();}
// -------------------------------------------------------------------
// Data Members:
// -------------------------------------------------------------------
int64_t objectUID_;
std::string objectName_;
int32_t granteeID_;
std::string granteeName_;
int32_t grantorID_;
std::string grantorName_;
int32_t columnOrdinal_;
PrivColumnBitmap privsBitmap_;
PrivColumnBitmap grantableBitmap_;
PrivMgrCoreDesc visited_;
PrivMgrCoreDesc current_;
};
// *****************************************************************************
// * Class: ColumnPrivsMDTable
// * Description: This class represents the COLUMN_PRIVILEGES table
// *
// * An column privileges row can be uniquely identified by:
// * objectUID
// * granteeID
// * grantorID
// * columnOrdinal
// *****************************************************************************
class ColumnPrivsMDTable : public PrivMgrMDTable
{
public:
ColumnPrivsMDTable(
const std::string & tableName,
ComDiagsArea * pDiags = NULL)
: PrivMgrMDTable(tableName,COLUMN_PRIVILEGES_ENUM, pDiags)
{};
virtual ~ColumnPrivsMDTable()
{};
virtual PrivStatus insert(const PrivMgrMDRow &row);
virtual PrivStatus selectWhereUnique(
const std::string & whereClause,
PrivMgrMDRow & row);
PrivStatus selectWhere(
const std::string & whereClause,
const std::string & orderByClause,
std::vector<PrivMgrMDRow *> &rowList);
PrivStatus updateColumnRow(
const ColumnPrivsMDRow & row,
const std::string whereBase);
private:
ColumnPrivsMDTable();
void setRow(
OutputInfo *pCliRow,
ColumnPrivsMDRow &rowOut);
};
// *****************************************************************************
// * PrivMgrPrivileges.cpp static function declarations *
// *****************************************************************************
static PrivStatus buildPrivText(
const std::vector<PrivMgrMDRow *> rowList,
const PrivMgrObjectInfo & objectInfo,
PrivLevel privLevel,
ComDiagsArea * pDiags_,
std::string & privilegeText);
void static buildGrantText(
const std::string & privText,
const std::string & objectGranteeText,
const int32_t grantorID,
const std::string grantorName,
bool isWGO,
const int32_t ownerID,
std::string & grantText);
void static closeColumnList(std::string & columnList);
static void deleteRowList(std::vector<PrivMgrMDRow *> & rowList);
static PrivMgrCoreDesc * findColumnEntry(
NAList<PrivMgrCoreDesc> & colPrivsToGrant,
const int32_t columnsOrdinal);
static void getColRowsForGranteeGrantor(
const std::vector <PrivMgrMDRow *> & columnRowList,
const int32_t granteeID,
const int32_t grantorID,
NAList<PrivMgrCoreDesc> &colPrivGrants);
static bool hasAllDMLPrivs(
ComObjectType objectType,
PrivObjectBitmap privBitmap);
static bool isDelimited( const std::string &identifier);
// *****************************************************************************
// PrivMgrPrivileges methods
// *****************************************************************************
// -----------------------------------------------------------------------
// Default Constructor
// -----------------------------------------------------------------------
PrivMgrPrivileges::PrivMgrPrivileges ()
: PrivMgr(),
objectUID_(0),
grantorID_(0)
{
objectTableName_ = metadataLocation_ + "." + PRIVMGR_OBJECT_PRIVILEGES;
columnTableName_ = metadataLocation_ + "." + PRIVMGR_COLUMN_PRIVILEGES;
}
// -----------------------------------------------------------------------
// Construct a PrivMgrPrivileges object for a new object privilege.
// -----------------------------------------------------------------------
PrivMgrPrivileges::PrivMgrPrivileges (
const int64_t objectUID,
const std::string &objectName,
const int32_t grantorID,
const std::string &metadataLocation,
ComDiagsArea * pDiags)
: PrivMgr(metadataLocation,pDiags),
objectUID_(objectUID),
objectName_(objectName),
grantorID_(grantorID)
{
objectTableName_ = metadataLocation + "." + PRIVMGR_OBJECT_PRIVILEGES;
columnTableName_ = metadataLocation + "." + PRIVMGR_COLUMN_PRIVILEGES;
}
// ----------------------------------------------------------------------------
// Construct PrivMgrPrivileges object for describe statements
// ----------------------------------------------------------------------------
PrivMgrPrivileges::PrivMgrPrivileges (
const PrivMgrObjectInfo &objectInfo,
const std::string &metadataLocation,
ComDiagsArea *pDiags)
: PrivMgr(metadataLocation, pDiags),
objectUID_(((PrivMgrObjectInfo)objectInfo).getObjectUID()),
objectName_(((PrivMgrObjectInfo)objectInfo).getObjectName()),
grantorID_(0)
{
objectTableName_ = metadataLocation + "." + PRIVMGR_OBJECT_PRIVILEGES;
columnTableName_ = metadataLocation + "." + PRIVMGR_COLUMN_PRIVILEGES;
}
// ----------------------------------------------------------------------------
// Construct a PrivMgrPrivileges object for an objectUID
// ----------------------------------------------------------------------------
PrivMgrPrivileges::PrivMgrPrivileges (
const int64_t objectUID,
const std::string &metadataLocation,
ComDiagsArea *pDiags)
: PrivMgr(metadataLocation, pDiags),
objectUID_(objectUID),
grantorID_(0)
{
objectTableName_ = metadataLocation + "." + PRIVMGR_OBJECT_PRIVILEGES;
columnTableName_ = metadataLocation + "." + PRIVMGR_COLUMN_PRIVILEGES;
}
// ----------------------------------------------------------------------------
// Construct a basic PrivMgrPrivileges object
// ----------------------------------------------------------------------------
PrivMgrPrivileges::PrivMgrPrivileges (
const std::string &metadataLocation,
ComDiagsArea *pDiags)
: PrivMgr(metadataLocation, pDiags),
objectUID_(0),
grantorID_(0)
{
objectTableName_ = metadataLocation + "." + PRIVMGR_OBJECT_PRIVILEGES;
columnTableName_ = metadataLocation + "." + PRIVMGR_COLUMN_PRIVILEGES;
}
// -----------------------------------------------------------------------
// Copy constructor
// -----------------------------------------------------------------------
PrivMgrPrivileges::PrivMgrPrivileges(const PrivMgrPrivileges &other)
: PrivMgr(other)
{
objectUID_ = other.objectUID_;
objectName_ = other.objectName_;
grantorID_ = other.grantorID_;
objectTableName_ = other.objectTableName_;
columnTableName_ = other.columnTableName_;
objectRowList_ = other.objectRowList_;
columnRowList_ = other.columnRowList_;
}
// -----------------------------------------------------------------------
// Destructor.
// -----------------------------------------------------------------------
PrivMgrPrivileges::~PrivMgrPrivileges()
{
deleteRowList(objectRowList_);
deleteRowList(columnRowList_);
}
// *****************************************************************************
// * Method: buildSecurityKeys
// *
// * Builds security keys for the current object and specified user.
// *
// * Parameters:
// *
// * <granteeID> is the unique identifier for the grantee
// * <privs> is the list of privileges the user has on the object
// * <secKeySet> is the set of security keys to be passed back. Caller is
// * responsible for freeing keys.
// *
// * Returns: PrivStatus
// *
// * STATUS_GOOD: Security keys were built
// * *: Security keys were not built, see diags.
// *
// *****************************************************************************
PrivStatus PrivMgrPrivileges::buildSecurityKeys(
const int32_t granteeID,
const PrivMgrCoreDesc &privs,
std::vector <ComSecurityKey *> & secKeySet)
{
if (privs.isNull())
return STATUS_GOOD;
// Only need to generate keys for DML privileges
for ( size_t i = FIRST_DML_PRIV; i <= LAST_DML_PRIV; i++ )
{
if ( privs.getPriv(PrivType(i)))
{
ComSecurityKey *key = NULL;
if (ComUser::isPublicUserID(granteeID))
key = new ComSecurityKey(granteeID,
ComSecurityKey::OBJECT_IS_SPECIAL_ROLE);
else
key = new ComSecurityKey(granteeID,
objectUID_,
PrivType(i),
ComSecurityKey::OBJECT_IS_OBJECT);
if (key->isValid())
secKeySet.push_back(key);
else
{
PRIVMGR_INTERNAL_ERROR("ComSecurityKey is null");
return STATUS_ERROR;
}
}
}
return STATUS_GOOD;
}
// *****************************************************************************
// * Method: getPrivsOnObject
// *
// * Creates a set of priv descriptors for all user grantees on an object
// * Used by Trafodion compiler to store as part of the table descriptor.
// *
// * Parameters:
// *
// * <objectType> is the type of object
// * <privDescs> is the list of privileges the on the object
// *
// * Returns: PrivStatus
// *
// * STATUS_GOOD: privilege descriptors were built
// * *: unexpected error occurred, see diags.
// *
// *****************************************************************************
PrivStatus PrivMgrPrivileges::getPrivsOnObject (
const ComObjectType objectType,
std::vector<PrivMgrDesc> & privDescs )
{
PrivStatus retcode = STATUS_GOOD;
if (objectUID_ == 0)
{
PRIVMGR_INTERNAL_ERROR("objectUID is 0 for getPrivRowsForObject()");
return STATUS_ERROR;
}
// generate the list of privileges granted to the object and store in class
if (generateObjectRowList() == STATUS_ERROR)
return STATUS_ERROR;
// generate the list of privileges granted to the column and store in class
if (generateColumnRowList() == STATUS_ERROR)
return STATUS_ERROR;
// Gets all the user grantees (userIDs) for the object and column lists
// Gets all the role grantees (roleIDs) for the object and column lists
// The public auth ID is included in the userIDs list
std::vector<int32_t> userIDs;
std::vector<int32_t> roleIDs;
if (getDistinctIDs(objectRowList_, columnRowList_, userIDs, roleIDs) == STATUS_ERROR)
return STATUS_ERROR;
// Gather privilege descriptors for each user
for (size_t i = 0; i < userIDs.size(); i++)
{
int32_t userID = userIDs[i];
PrivMgrDesc privsOfTheUser(userID);
bool hasManagePrivileges = false;
std::vector <int32_t> emptyRoleIDs;
// getUserPrivs returns object and column privileges summarized across all
// grantors. Just get direct grants to the user (role list is empty)
if (getUserPrivs(objectType, userID, emptyRoleIDs, privsOfTheUser,
hasManagePrivileges, NULL ) != STATUS_GOOD)
return STATUS_ERROR;
if (!privsOfTheUser.isNull())
privDescs.push_back(privsOfTheUser);
}
// Attach roles to priv lists
for (size_t i = 0; i < roleIDs.size(); i++)
{
int32_t grantee = roleIDs[i];
PrivMgrDesc privsOfTheUser(grantee);
bool hasManagePrivileges = false;
std::vector <int32_t> emptyRoleIDs;
// getUserPrivs returns object and column privileges summarized across
// all grantors.
if (getUserPrivs(objectType, grantee, emptyRoleIDs, privsOfTheUser,
hasManagePrivileges, NULL ) != STATUS_GOOD)
return STATUS_ERROR;
if (!privsOfTheUser.isNull())
privDescs.push_back(privsOfTheUser);
}
return STATUS_GOOD;
}
// *****************************************************************************
// Function: getColRowsForGranteeOrdinal
//
// Returns the list of column privileges granted for the object that have
// been granted to the granteeID for a particular column
//
// Parameters:
//
// <granteeID> is the authID granted the privileges.
// <columnOrdinal> is the column number to gather privileges
// <columnRowList> is the list of column privs for the object
// <roleIDs> is the list of roles assigned the granteeID
// <rowList> the privileges granted to <granteeID> on <columnOrdinal>.
//
// *****************************************************************************
void PrivMgrPrivileges::getColRowsForGranteeOrdinal(
const int32_t granteeID,
const int32_t columnOrdinal,
const std::vector <PrivMgrMDRow *> &columnRowList,
const std::vector<int32_t> &roleIDs,
std::vector<PrivMgrMDRow *> &rowList)
{
for (size_t i = 0; i < columnRowList.size(); ++i)
{
ColumnPrivsMDRow &row = static_cast<ColumnPrivsMDRow &> (*columnRowList[i]);
PrivMgrCoreDesc colPrivGrant;
if (row.columnOrdinal_ == columnOrdinal)
{
if (row.granteeID_ == granteeID ||
std::find(roleIDs.begin(), roleIDs.end(), row.granteeID_) != roleIDs.end())
{
ColumnPrivsMDRow *pRow = new ColumnPrivsMDRow();
*pRow = row;
rowList.push_back(pRow);
}
}
}
}
// *****************************************************************************
// * Method: getDistinctIDs
// *
// * Finds all the userIDs that have been granted at least one privilege on
// * object. This list includes the public authorization ID
// *
// * Finds all the roleIDs that have been granted at least one privilege on
// * object
// *****************************************************************************
PrivStatus PrivMgrPrivileges::getDistinctIDs(
const std::vector <PrivMgrMDRow *> &objectRowList,
const std::vector <PrivMgrMDRow *> &columnRowList,
std::vector<int32_t> &userIDs,
std::vector<int32_t> &roleIDs)
{
int32_t authID;
// DB__ROOTROLE is a special role. If the current user has been granted
// this role, then they have privileges. Add it to the roleIDs list for
// processing.
roleIDs.push_back(ROOT_ROLE_ID);
// The direct object grants are stored in memory (objectRowList) so no I/O
for (size_t i = 0; i < objectRowList.size(); i++)
{
ObjectPrivsMDRow &row = static_cast<ObjectPrivsMDRow &> (*objectRowList[i]);
authID = row.granteeID_;
// insert authID into correct list, if not already present
if (ComUser::isPublicUserID(authID) || CmpSeabaseDDLauth::isUserID(authID))
{
if (std::find(userIDs.begin(), userIDs.end(), authID) == userIDs.end())
userIDs.insert( std::upper_bound( userIDs.begin(), userIDs.end(), authID ), authID);
}
else
{
if (std::find(roleIDs.begin(), roleIDs.end(), authID) == roleIDs.end())
roleIDs.insert( std::upper_bound( roleIDs.begin(), roleIDs.end(), authID ), authID);
}
}
// The direct column grants are stored in memory (columnRowList) so no I/O
// Save grants to roles for further processing
for (size_t i = 0; i < columnRowList.size(); i++)
{
ColumnPrivsMDRow &row = static_cast<ColumnPrivsMDRow &> (*columnRowList[i]);
authID = row.granteeID_;
// insert authID into correct list, if not already present
if (ComUser::isPublicUserID(authID) ||
CmpSeabaseDDLauth::isUserID(authID))
{
if (std::find(userIDs.begin(), userIDs.end(), authID) == userIDs.end())
userIDs.insert( std::upper_bound( userIDs.begin(), userIDs.end(), authID ), authID);
}
else
{
if (std::find(roleIDs.begin(), roleIDs.end(), authID) == roleIDs.end())
roleIDs.insert( std::upper_bound( roleIDs.begin(), roleIDs.end(), authID ), authID);
}
}
return STATUS_GOOD;
}
// *****************************************************************************
// * Method: getPrivRowsForObject
// *
// * returns rows describing all the privileges that have been
// * granted on the object
// *
// * Parameters:
// *
// * <objectPrivsRows> Zero or more rows of grants for the object.
// *
// * Returns: PrivStatus
// *
// * STATUS_GOOD : Rows were returned
// * STATUS_NOTFOUND: No rows were returned
// * *: Unable to read privileges, see diags.
// *
// *****************************************************************************
PrivStatus PrivMgrPrivileges::getPrivRowsForObject(
const int64_t objectUID,
std::vector<ObjectPrivsRow> & objectPrivsRows)
{
PrivStatus retcode = STATUS_GOOD;
if (objectUID_ == 0)
{
PRIVMGR_INTERNAL_ERROR("objectUID is 0 for getPrivRowsForObject()");
return STATUS_ERROR;
}
// generate the list of privileges granted to the object and store in class
if (generateObjectRowList() == STATUS_ERROR)
return STATUS_ERROR;
for (size_t i = 0; i < objectRowList_.size(); i++)
{
ObjectPrivsMDRow &row = static_cast<ObjectPrivsMDRow &> (*objectRowList_[i]);
if (row.grantorID_ != SYSTEM_USER)
{
ObjectPrivsRow newRow;
strcpy(newRow.objectName,row.objectName_.c_str());
newRow.objectType = row.objectType_;
newRow.granteeID = row.granteeID_;
strcpy(newRow.granteeName,row.granteeName_.c_str());
newRow.granteeType = CmGetComGranteeAsGranteeType(row.granteeType_.c_str());
newRow.grantorID = row.grantorID_;
strcpy(newRow.grantorName,row.grantorName_.c_str());
newRow.grantorType = CmGetComGrantorAsGrantorType(row.grantorType_.c_str());
newRow.privilegesBitmap = row.privsBitmap_.to_ulong();
newRow.grantableBitmap = row.grantableBitmap_.to_ulong();
objectPrivsRows.push_back(newRow);
}
}
return retcode;
}
// ----------------------------------------------------------------------------
// method: getTreeOfGrantors
//
// Returns the list of grantors that have granted privileges to the grantee,
// either directly or through another grantor in the tree.
//
// The list is determined by first looking at the direct grantors. For each
// returned grantor, this function is called recursively to get the previous set
// of grantors until there are no more grantors.
//
// The list is returned in grantor ID order.
//
// For example:
// user1 (owner) grants to:
// user6 who grants to:
// user3
// user4 who grants to:
// user5
// user2
// user3 who grants to:
// user4
// user5
// The following grantors are returned for granteeID user4:
// user1, user3, user6
//
// Params:
// granteeID - where to start the search
// listOfGrantors - returns the list of grantors
// ----------------------------------------------------------------------------
void PrivMgrPrivileges::getTreeOfGrantors(
const int32_t granteeID,
std::set<int32_t> &listOfGrantors)
{
// search the rowList for a match
for (size_t i = 0; i < objectRowList_.size(); i++)
{
ObjectPrivsMDRow &row = static_cast<ObjectPrivsMDRow &> (*objectRowList_[i]);
if (row.granteeID_ == granteeID)
{
// We found a grant to the granteeID
// go up to the next level using the grantorID
getTreeOfGrantors( row.grantorID_, listOfGrantors);
listOfGrantors.insert(granteeID);
}
}
}
// *****************************************************************************
// * Method: givePrivForObjects
// *
// * Updates one or more rows in the OBJECT_PRIVILEGES table to reflect
// * a new owner of one or more objects.
// *
// * Parameters:
// *
// * <currentOwnerID> is the unique identifier for the current owner
// * <newOwnerID> is the unique identifier for the new owner
// * <newOwnerName> is the name of the new owner (upper cased)
// * <objectUIDs> is the list of objects with a new owner
// *
// * Returns: PrivStatus
// *
// * STATUS_GOOD: Privileges were updated to reflect new owner
// * *: Unable to update privileges, see diags.
// *
// *****************************************************************************
PrivStatus PrivMgrPrivileges::givePrivForObjects(
const int32_t currentOwnerID,
const int32_t newOwnerID,
const std::string &newOwnerName,
const std::vector<int64_t> &objectUIDs)
{
PrivStatus privStatus = STATUS_GOOD;
for (size_t i = 0; i < objectUIDs.size(); i++)
{
privStatus = givePriv(currentOwnerID,newOwnerID,newOwnerName,objectUIDs[i]);
if (privStatus != STATUS_GOOD)
return privStatus;
}
return STATUS_GOOD;
}
// *****************************************************************************
// * Method: givePriv
// *
// * Updates rows in the OBJECT_PRIVILEGES table to reflect a new owner of
// * an objects.
// *
// * Parameters:
// *
// * <granteeID> is the unique identifier for the new owner
// * <granteeName> is the name of the new owner (upper cased)
// * <objectUIDs> is the list of objects with a new owner
// *
// * Returns: PrivStatus
// *
// * STATUS_GOOD: Privileges were updated to reflect new owner
// * *: Unable to update privileges, see diags.
// *
// *****************************************************************************
PrivStatus PrivMgrPrivileges::givePriv(
const int32_t currentOwnerID,
const int32_t newOwnerID,
const std::string &newOwnerName,
const int64_t objectUID)
{
// *****************************************************************************
// * *
// * The set of grants for a given object can be thought of as a tree with *
// * many branches and one root. At the root, is the grant from the system *
// * (grantor is _SYSTEM) to the owner of the object. The grant from the *
// * system is for all privileges, with grant option. *
// * *
// * The owner then grants privileges to one or more authIDs. Each of *
// * these grants can be viewed as a branch off the system grant root. With *
// * WITH GRANT OPTION, each of these branches can have its own set of *
// * branches, potentially resulting in a dense tree. See the rough *
// * drawing: *
// * *
// * USERG USERC USERD USERC USERB *
// * \ | / \ | / *
// * \ | / \ | / *
// * \ | / \ | / *
// * USERE USERD USERF USERB USERG *
// * \ | / \ | / *
// * \ | / \ | / *
// * \ | / \ | / *
// * USERB USERC USERD *
// * \ | / *
// * \ | / *
// * \ | / *
// * USERA *
// * | *
// * _SYSTEM *
// * *
// * *
// * Some of the rules are: *
// * 1) No grants to the owner (USERA) *
// * 2) A user can appear an unlimited number of times in the tree, but *
// * all grants from the user (for a given privilege) are from the same *
// * node. For example, USERB is granted 3 times, but all grants from *
// * USERB emanate from the same node. This is because when USERB grants *
// * a privilege, we start from the root and find the first node where *
// * USERB has WITH GRANT OPTION. *
// * *
// * When an object is given to another user, the current owner loses *
// * their grant from the system; instead, the new owner is granted from the *
// * system. All existing grants from the current owner are now from the new *
// * owner. Based on rule #1 above, the new owner can no longer appear in *
// * other nodes in the tree except the root node. So, in the case where the *
// * object is given to USERB, the new grant tree should be: *
// * *
// * USERD USERC *
// * | \ | *
// * | \ | *
// * USERC | \ | *
// * \ | USERF USERG *
// * \ | | \ / *
// * \ | | \ / *
// * \ | | \ / *
// * USERG ---------USERE | USERD *
// * \ | / *
// * \ | / *
// * \ | / *
// * USERB ---- USERC *
// * | *
// * _SYSTEM *
// * *
// * *
// * Note, previously USERA had three grants, and USERB had three grants, *
// * and now USERB has four grants--not six. First, the grant from USERA to *
// * USERB is removed. USERB is the grantee on only one node, from the system *
// * Second, USERA and USERB both had a grant to USERD; these grants need to *
// * be combined. *
// * *
// * Essentially, the subtree (or branch) of USERB has been grafted into *
// * the root, and all USERB leaf nodes have been removed. Any duplicate *
// * nodes, where USERA and USERB were grantors to the same grantee, have *
// * been merged. *
// * *
// * The algorithm is therefore three steps: *
// * *
// * 1) Delete any leaf nodes where the new owner is the grantee. *
// * 2) Get the list of nodes where the original or the new owner is the *
// * grantor. Merge any duplicates (update bitmaps), and update to new *
// * owner for old nodes. *
// * 3) Update grantee on system grant to new owner. *
// * *
// *****************************************************************************
//
// Delete the leaf nodes:
//
// DELETE FROM OBJECT_PRIVIELGES
// WHERE OBJECT_UID = objectUID and GRANTEE_ID = granteeID
//
PrivStatus privStatus = STATUS_GOOD;
ObjectPrivsMDTable objectPrivsTable(objectTableName_,pDiags_);
std::vector<PrivMgrMDRow *> rowList;
char buf[1000];
sprintf(buf,"WHERE object_uid = %ld AND grantee_ID = %d",
objectUID,newOwnerID);
privStatus = objectPrivsTable.deleteWhere(buf);
if (privStatus != STATUS_GOOD)
return privStatus;
sprintf(buf, "WHERE object_uid = %ld AND (grantor_ID = %d OR grantor_ID = %d) ",
objectUID,newOwnerID,currentOwnerID);
std::string orderByClause (" ORDER BY grantee_ID ");
privStatus = objectPrivsTable.selectWhere(buf, orderByClause ,rowList);
if (privStatus != STATUS_GOOD)
{
deleteRowList(rowList);
return privStatus;
}
for (size_t i = rowList.size(); i > 0; i--)
{
ObjectPrivsMDRow &currentRow = static_cast<ObjectPrivsMDRow &>(*rowList[i - 1]);
if (i == 1 && currentRow.grantorID_ == currentOwnerID)
{
currentRow.grantorID_ = newOwnerID;
currentRow.grantorName_ = newOwnerName;
privStatus = objectPrivsTable.updateRow(currentRow);
if (privStatus != STATUS_GOOD)
{
deleteRowList(rowList);
return privStatus;
}
continue;
}
ObjectPrivsMDRow &previousRow = static_cast<ObjectPrivsMDRow &>(*rowList[i - 1]);
// If both granted to the same ID, merge the rows, delete one,
// and update the other.
if (currentRow.granteeID_ == previousRow.granteeID_)
{
previousRow.privsBitmap_ |= currentRow.privsBitmap_;
previousRow.grantableBitmap_ |= currentRow.grantableBitmap_;
previousRow.grantorID_ = newOwnerID;
previousRow.grantorName_ = newOwnerName;
privStatus = objectPrivsTable.deleteRow(currentRow);
if (privStatus != STATUS_GOOD)
{
deleteRowList(rowList);
return privStatus;
}
privStatus = objectPrivsTable.updateRow(previousRow);
if (privStatus != STATUS_GOOD)
{
deleteRowList(rowList);
return privStatus;
}
i--;
continue;
}
// If this is a grant from the old owner, update to the new owner.
if (currentRow.grantorID_ == currentOwnerID)
{
currentRow.grantorID_ = newOwnerID;
currentRow.grantorName_ = newOwnerName;
privStatus = objectPrivsTable.updateRow(currentRow);
if (privStatus != STATUS_GOOD)
{
deleteRowList(rowList);
return privStatus;
}
continue;
}
// Grant from the new owner. Will automatically be grafted into the
// tree in the next step.
}
deleteRowList(rowList);
// Update the root node.
char setClause[1000];
char whereClause[1000];
sprintf(setClause," SET GRANTEE_ID = %d, GRANTEE_NAME = '%s' ",
newOwnerID,newOwnerName.c_str());
sprintf(whereClause," WHERE GRANTOR_ID = %d ",SYSTEM_USER);
privStatus = objectPrivsTable.updateWhere(setClause,whereClause);
if (privStatus != STATUS_GOOD)
return privStatus;
return STATUS_GOOD;
}
// *****************************************************************************
// * Method: grantColumnPriv
// *
// * Adds or updates a row in the COLUMN_PRIVILEGES table.
// *
// * Parameters:
// *
// * <objectType> is the type of the subject object.
// * <granteeID> is the unique identifier for the grantee
// * <granteeName> is the name of the grantee (upper cased)
// * <grantorName> is the name of the grantor (upper cased)
// * <colPrivsArray> is the list of columns and privileges to grant
// * <isWGOSpecified> is true then also allow the grantee to grant the set
// * of privileges to other grantees
// *
// * Returns: PrivStatus
// *
// * STATUS_GOOD: Privileges were granted
// * *: Unable to grant privileges, see diags.
// *
// *****************************************************************************
PrivStatus PrivMgrPrivileges::grantColumnPriv(
const ComObjectType objectType,
const int32_t granteeID,
const std::string &granteeName,
const std::string &grantorName,
const PrivMgrDesc &privsToGrant,
const bool isWGOSpecified)
{
std::string traceMsg;
PrivStatus privStatus = STATUS_GOOD;
log (__FILE__, "Checking column privileges", -1);
NAList<PrivMgrCoreDesc> colPrivsToGrant = privsToGrant.getColumnPrivs();
// Verify that view-col <=> referenced_col relationship exists
if (objectType == COM_VIEW_OBJECT)
{
ViewUsage myUsage;
myUsage.viewUID = objectUID_;
PrivMgrMDAdmin admin(trafMetadataLocation_, metadataLocation_, pDiags_);
if (admin.getViewColUsages(myUsage) == STATUS_ERROR)
return STATUS_ERROR;
if (myUsage.viewColUsagesStr.empty())
{
*pDiags_ << DgSqlCode (-CAT_COLUMN_PRIVILEGE_NOT_ALLOWED)
<< DgTableName (objectName_.c_str());
return STATUS_ERROR;
}
}
bool rowWritten = false;
std::string whereBase(" WHERE object_uid = ");
whereBase += UIDToString(objectUID_);
whereBase += " AND grantor_id = ";
whereBase += authIDToString(grantorID_);
whereBase += " AND grantee_id = ";
whereBase += authIDToString(granteeID);
whereBase += " AND column_number = ";
ColumnPrivsMDTable columnPrivsTable(columnTableName_,pDiags_);
// Get privileges on the object for grantor/grantee
ObjectPrivsMDRow objRow;
PrivObjectBitmap objPrivsBitmap;
PrivObjectBitmap objGrantableBitmap;
privStatus = getGrantedPrivs(granteeID, objRow);
// getGrantedPrivs returns STATUS_GOOD or STATUS_NOTFOUND
// if STATUS_NOTFOUND, bitmaps are empty (as initialized above)
// if STATUS_GOOD, set current bitmaps
if (privStatus == STATUS_GOOD)
{
objPrivsBitmap = objRow.privsBitmap_;
objGrantableBitmap = objRow.grantableBitmap_;
}
// Get existing column grants from grantor to the specified grantee.
NAList<PrivMgrCoreDesc> grantedColPrivs(STMTHEAP);
getColRowsForGranteeGrantor(columnRowList_,
granteeID,grantorID_,
grantedColPrivs);
// Walk the list of column privileges to grant, and either insert a new
// row in the COLUMN_PRIVILEGES table or update an existing row.
for (size_t i = 0; i < colPrivsToGrant.entries(); i++)
{
PrivMgrCoreDesc &colPrivToGrant = colPrivsToGrant[i];
// TBD - add a describe function to PrivMgrCoreDesc and PrivMgrDesc so
// information can ge logged.
bool updateOperation = false;
bool skipOperation = false;
PrivMgrCoreDesc *grantedColPriv = findColumnEntry(grantedColPrivs, colPrivToGrant.getColumnOrdinal());
if (grantedColPriv)
{
// An existing row with the same column has been found, it is one of four cases:
//
// 1) AuthID had WGO, now trying to take away WGO [error]
// 2) Adding a privilege (e.g., authID had SELECT, now granting INSERT) [update operation]
// 3) AuthID had privilege, now adding WGO [update operation]
// 4) AuthID already has privilege and/or WGO specified [skip operation]
// case 1: see if trying to take away WGO - anyNotSet returns true iff any
// WGO bit set in grantedColPriv is not set in colPrivToGrant - can this
// really occur?
if (colPrivToGrant.getPrivBitmap() == grantedColPriv->getPrivBitmap() &&
grantedColPriv->anyNotSet(colPrivToGrant))
{
PRIVMGR_INTERNAL_ERROR("trying to remove WGO during grant");
return STATUS_ERROR;
}
// Case 2: If the privilege bitmaps are not the same, adding a privilege.
// This is an update operation
if (colPrivToGrant.getPrivBitmap() != grantedColPriv->getPrivBitmap())
{
updateOperation = true;
colPrivToGrant.unionOfPrivs(*grantedColPriv);
}
else
// Case 3: the privileges match, see if there are any additional WGO privs
// to set and mark updatable
// anyNotSet returns true iff any WGO bit set in colPrivToGrant is not set in
// grantedColPriv, this means more WGO bits need to be set.
if (colPrivToGrant.anyNotSet(*grantedColPriv))
{
updateOperation = true;
colPrivToGrant.unionOfPrivs(*grantedColPriv);
}
// Case 4: no changes to priv or WGO bits - no updates required - skip
else
skipOperation = true;
}
// Done with this entry, go to the next one
if (skipOperation)
continue;
// Create an ObjectUsage to propagate the privilege change to dependent
// objects
ObjectUsage objectUsage;
objectUsage.objectUID = objectUID_;
objectUsage.granteeID = granteeID;
objectUsage.objectName = objectName_;
objectUsage.objectType = objectType;
PrivMgrCoreDesc currentPrivs; // creates an empty descriptor
PrivMgrCoreDesc tempPrivs(objPrivsBitmap, objGrantableBitmap);
objectUsage.originalPrivs.setTablePrivs(tempPrivs);
objectUsage.updatedPrivs.setTablePrivs(tempPrivs);
// Create list of ColumnReferences
objectUsage.columnReferences = new std::vector<ColumnReference *>;
for (size_t i = 0; i < colPrivsToGrant.entries(); i++)
{
PrivMgrCoreDesc &colPrivToGrant = colPrivsToGrant[i];
PrivMgrCoreDesc *grantedColPriv = findColumnEntry(grantedColPrivs, colPrivToGrant.getColumnOrdinal());
ColumnReference *adjustedCol = new ColumnReference;
adjustedCol->columnOrdinal = colPrivToGrant.getColumnOrdinal();
PrivMgrCoreDesc adjustedPrivs;
if (grantedColPriv)
adjustedPrivs = *grantedColPriv;
adjustedCol->originalPrivs = adjustedPrivs;
adjustedPrivs.unionOfPrivs(colPrivToGrant);
adjustedCol->updatedPrivs = adjustedPrivs;
objectUsage.columnReferences->push_back(adjustedCol);
}
// Propagate the privilege change to dependent objects
if (updateDependentObjects(objectUsage, PrivCommand::GRANT_COLUMN) == STATUS_ERROR)
return STATUS_ERROR;
// Update the COLUMN_PRIVILEGES table with new privileges
// Prepare for the insert or update request
ColumnPrivsMDRow row;
row.objectUID_ = objectUID_;
row.objectName_ = objectName_;
row.granteeID_ = granteeID;
row.granteeName_ = granteeName;
row.grantorID_ = grantorID_;
row.grantorName_ = grantorName;
row.privsBitmap_ = colPrivToGrant.getPrivBitmap();
row.grantableBitmap_ = colPrivToGrant.getWgoBitmap();
row.columnOrdinal_ = colPrivToGrant.getColumnOrdinal();
if (updateOperation)
privStatus = columnPrivsTable.updateColumnRow(row,whereBase);
else
privStatus = columnPrivsTable.insert(row);
if (privStatus == STATUS_ERROR)
return privStatus;
rowWritten = true;
}
return STATUS_GOOD;
}
//************* End of PrivMgrPrivileges::grantColumnPriv ****************
// *****************************************************************************
// * Method: grantObjectPriv
// *
// * Adds or updates a row in the OBJECT_PRIVILEGES table.
// *
// * Parameters:
// *
// * <objectType> is the type of the subject object.
// * <granteeID> is the unique identifier for the grantee
// * <granteeName> is the name of the grantee (upper cased)
// * <grantorName> is the name of the grantor (upper cased)
// * <privsList> is the list of privileges to grant
// * <colPrivsArray> is the list of columns and privileges to grant
// * <isAllSpecified> if true then all privileges valid for the object
// * type will be granted
// * <isWGOSpecified> is true then also allow the grantee to grant the set
// * of privileges to other grantees
// *
// * Returns: PrivStatus
// *
// * STATUS_GOOD: Privileges were granted
// * *: Unable to grant privileges, see diags.
// *
// *****************************************************************************
PrivStatus PrivMgrPrivileges::grantObjectPriv(
const ComObjectType objectType,
const int32_t granteeID,
const std::string &granteeName,
const std::string &grantorName,
const std::vector<PrivType> &privsList,
const std::vector<ColPrivSpec> & colPrivsArray,
const bool isAllSpecified,
const bool isWGOSpecified)
{
PrivStatus retcode = STATUS_GOOD;
std::string traceMsg;
log (__FILE__, "****** GRANT operation begins ******", -1);
// If this grant request is called during the creation of the OBJECT_PRIVILEGES
// table, just return okay. Fixes a chicken and egg problem.
char theQuote = '"';
std::string nameRequested(objectName_);
std::string nameToCheck(objectTableName_);
// Delimited name issue. The passed in objectName may enclose name parts in
// double quotes even if the name part contains only [a-z][A-Z][0-9]_
// characters. The same is true for the stored metadataLocation_.
// To allow equality checks to work, we strip off the double quote delimiters
// from both names. Fortunately, the double quote character is not allowed in
// any SQL identifier except as delimiters - so this works.
nameRequested.erase(std::remove(nameRequested.begin(), nameRequested.end(), theQuote), nameRequested.end());
nameToCheck.erase(std::remove(nameToCheck.begin(), nameToCheck.end(), theQuote), nameToCheck.end());
if (nameRequested == nameToCheck && grantorID_ == SYSTEM_USER)
return STATUS_GOOD;
// If the granting to self or DB__ROOT, return an error
if (grantorID_ == granteeID || granteeID == ComUser::getRootUserID())
{
*pDiags_ << DgSqlCode(-CAT_CANT_GRANT_TO_SELF_OR_ROOT);
return STATUS_ERROR;
}
PrivMgrDesc privsToGrant(granteeID);
PrivMgrDesc privsOfTheGrantor(grantorID_);
std::vector<int_32> roleIDs;
retcode = initGrantRevoke(objectType, granteeID, grantorName,
privsList, colPrivsArray,
isAllSpecified, isWGOSpecified, true,
privsToGrant, privsOfTheGrantor, roleIDs);
if (retcode != STATUS_GOOD)
return retcode;
// Make sure the grantor can grant at least one of the requested privileges
// SQL Ansi states that privileges that can be granted should be done so
// even if some requested privilege are not grantable.
// Remove any privsToGrant which are not held GRANTABLE by the Grantor.
bool warnNotAll = false;
PrivMgrDesc origPrivsToGrant = privsToGrant;
// if limitToGrantable true ==> some specified privs were not grantable.
if ( privsToGrant.limitToGrantable( privsOfTheGrantor ) )
warnNotAll = true;
// If nothing left to grant, we are done.
// If one of the users roles has privilege, indicate in error message
if ( privsToGrant.isNull() )
{
std::string rolesWithPrivs;
if (getRolesToCheck(grantorID_, roleIDs, objectType, rolesWithPrivs)== STATUS_GOOD)
{
if (rolesWithPrivs.size() > 0)
{
*pDiags_ << DgSqlCode (-CAT_PRIVILEGE_NOT_GRANTED)
<< DgString0 (grantorName.c_str())
<< DgString1 (rolesWithPrivs.c_str());
return STATUS_ERROR;
}
}
*pDiags_ << DgSqlCode (-CAT_PRIVILEGE_NOT_GRANTED)
<< DgString0 (grantorName.c_str());
return STATUS_ERROR;
}
// grant any column level privileges
if ( !privsToGrant.isColumnLevelNull() )
{
retcode = grantColumnPriv(objectType,granteeID,granteeName,grantorName,
privsToGrant,isWGOSpecified);
if (retcode != STATUS_GOOD)
return retcode;
}
// If only column-level privileges were specified, no problem.
if (privsToGrant.getTablePrivs().isNull())
{
// report any privs not granted
if (warnNotAll)
reportPrivWarnings(origPrivsToGrant,
privsToGrant,
CAT_NOT_ALL_PRIVILEGES_GRANTED);
log (__FILE__, "****** GRANT operation succeeded ******", -1);
return STATUS_GOOD;
}
// check for circular dependency. If USERX grants to USERY WGO, then USERY
// cannot grant back to USERX. Theoretically, USERX can grant select, update
// to USERY and USERY can grant delete, insert to USERX but for simplicity,
// we will reject the request independent on the set of privileges involved.
std::set<int32_t> listOfGrantors;
getTreeOfGrantors(grantorID_, listOfGrantors);
// If we find the grantee in the list of grantors, return an error
if (listOfGrantors.find(granteeID) != listOfGrantors.end())
{
*pDiags_ << DgSqlCode(-CAT_CIRCULAR_PRIVS)
<< DgString0(grantorName.c_str())
<< DgString1(granteeName.c_str());
return STATUS_ERROR;
}
// See if grantor has previously granted privileges to the grantee
bool foundRow = false;
ObjectPrivsMDRow row;
retcode = getGrantedPrivs(granteeID, row);
if (retcode == STATUS_NOTFOUND)
foundRow = false;
else if (retcode == STATUS_GOOD)
foundRow = true;
else
return retcode;
// if privileges exist, set currentPrivs to existing list
PrivMgrCoreDesc currentPrivs; // creates an empty descriptor
if (foundRow)
{
PrivMgrCoreDesc tempPrivs(row.privsBitmap_, row.grantableBitmap_);
currentPrivs = tempPrivs;
}
PrivMgrCoreDesc savedOriginalPrivs = currentPrivs;
// get the list of additional privileges to grant
// some privileges may have already been granted
PrivMgrDesc privsToAdd = privsToGrant;
PrivMgrCoreDesc::PrivResult result = privsToAdd.grantTablePrivs(currentPrivs);
// nothing to grant - everything is already granted
if ( result == PrivMgrCoreDesc::NONE )
{
if (warnNotAll)
reportPrivWarnings(origPrivsToGrant,
privsToGrant,
CAT_NOT_ALL_PRIVILEGES_GRANTED);
return STATUS_GOOD;
}
// Internal consistency check. We should have granted something.
assert( result != PrivMgrCoreDesc::NEUTRAL );
// There is something to grant, update/insert metadata
// set up row if it does not exist and add it to the objectRowList
if (!foundRow)
{
ObjectPrivsMDRow *pRow = new ObjectPrivsMDRow();
pRow->objectUID_ = objectUID_;
pRow->objectName_ = objectName_;
pRow->objectType_ = objectType;
pRow->granteeID_ = granteeID;
pRow->granteeName_ = granteeName;
pRow->granteeType_ = USER_GRANTEE_LIT;
pRow->grantorID_ = grantorID_;
pRow->grantorName_ = grantorName;
pRow->grantorType_ = USER_GRANTOR_LIT;
pRow->privsBitmap_.reset();
pRow->grantableBitmap_.reset();
objectRowList_.push_back(pRow);
row = *pRow;
}
// combine privsToGrant with existing privs
else
{
privsToGrant.unionOfPrivs(currentPrivs);
row.privsBitmap_ = privsToGrant.getTablePrivs().getPrivBitmap();
row.grantableBitmap_ = privsToGrant.getTablePrivs().getWgoBitmap();
}
// Update dependent objects
ObjectUsage objectUsage;
objectUsage.objectUID = objectUID_;
objectUsage.granteeID = granteeID;
objectUsage.grantorIsSystem = false;
objectUsage.objectName = row.objectName_;
objectUsage.objectType = row.objectType_;
objectUsage.columnReferences = NULL;
PrivMgrDesc originalPrivs (row.granteeID_);
originalPrivs.setTablePrivs(savedOriginalPrivs);
objectUsage.originalPrivs = originalPrivs;
objectUsage.updatedPrivs = privsToGrant;
if (updateDependentObjects(objectUsage, PrivCommand::GRANT_OBJECT) == STATUS_ERROR)
return STATUS_ERROR;
ObjectPrivsMDTable objectPrivsTable (objectTableName_, pDiags_);
if (foundRow)
{
row.describeRow(traceMsg);
traceMsg.insert(0, "updating existing privilege row ");
log (__FILE__, traceMsg, -1);
// update the row
retcode = objectPrivsTable.updateRow(row);
}
else
{
row.privsBitmap_ = privsToGrant.getTablePrivs().getPrivBitmap();
row.grantableBitmap_ = privsToGrant.getTablePrivs().getWgoBitmap();
row.describeRow(traceMsg);
traceMsg.insert(0, "adding new privilege row ");
log (__FILE__, traceMsg, -1);
// insert the row
retcode = objectPrivsTable.insert(row);
}
if (warnNotAll)
reportPrivWarnings(origPrivsToGrant,
privsToGrant,
CAT_NOT_ALL_PRIVILEGES_GRANTED);
log (__FILE__, "****** GRANT operation succeeded ******", -1);
return retcode;
}
// *****************************************************************************
// * Method: grantObjectPriv
// *
// * Adds or update a row in the OBJECT_PRIVILEGES table representing the
// * owner privileges. The privileges and grantable bitmaps as passed in.
// *
// * Parameters:
// *
// * <objectType> is the type of the subject object.
// * <granteeID> is the unique identifier for the grantee
// * <granteeName> is the name of the grantee (upper cased)
// * <privBitmap> is the list of privileges to grant
// * <grantableBitmap> is the grantable privileges to grant
// *
// * Returns: PrivStatus
// *
// * STATUS_GOOD: Privileges were granted
// * *: Unable to grant privileges, see diags.
// *
// *****************************************************************************
PrivStatus PrivMgrPrivileges::grantObjectPriv(
const ComObjectType objectType,
const int32_t granteeID,
const PrivObjectBitmap privsBitmap,
const PrivObjectBitmap grantableBitmap)
{
PrivStatus retcode = STATUS_GOOD;
if (objectUID_ == 0)
{
PRIVMGR_INTERNAL_ERROR("objectUID is 0 for grant command");
return STATUS_ERROR;
}
// get the associated grantorName and granteeName
std::string grantorName;
if (!getAuthNameFromAuthID(grantorID_, grantorName))
return STATUS_ERROR;
std::string granteeName;
if (!getAuthNameFromAuthID(granteeID, granteeName))
return STATUS_ERROR;
// set up the values of the row to insert
ObjectPrivsMDRow row;
row.objectUID_ = objectUID_;
row.objectName_ = objectName_;
row.objectType_ = objectType;
row.granteeID_ = granteeID;
row.granteeName_ = granteeName;
row.granteeType_ = USER_GRANTEE_LIT;
row.grantorID_ = grantorID_;
row.grantorName_ = grantorName;
row.grantorType_ = (grantorID_ == SYSTEM_USER) ? SYSTEM_GRANTOR_LIT : USER_GRANTOR_LIT;
row.privsBitmap_ = privsBitmap;
row.grantableBitmap_ = grantableBitmap;
// Insert the new row, the row should not exist since the request
// is coming during the creation of a new object.
ObjectPrivsMDTable objectPrivsTable (objectTableName_, pDiags_);
retcode = objectPrivsTable.insert(row);
return retcode;
}
// *****************************************************************************
// * Method: grantToOwners
// *
// * Performs the initial grant from the system to the owner. For private
// * schemas, where the creator is not the schema/object owner, a grant from
// * the object owner to the creator is also performed.
// *
// * Parameters:
// *
// * <objectType> is the type of the subject object.
// * <granteeID> is the unique identifier for the grantee
// * <granteeName> is the name of the grantee (upper cased)
// * <ownerID> is the unique identifier for the owner of the object
// * <ownerName> is the name of the owner (upper cased)
// * <creatorID> is the unique identifier for the creator of the object
// * <creatorName> is the name of the creator (upper cased)
// *
// * Returns: PrivStatus
// *
// * STATUS_GOOD: All DML privs were granted
// * *: Not all privs were granted. Error in CLI diags area.
// *
// *****************************************************************************
PrivStatus PrivMgrPrivileges::grantToOwners(
const ComObjectType objectType,
const Int32 granteeID,
const std::string & granteeName,
const Int32 ownerID,
const std::string & ownerName,
const Int32 creatorID,
const std::string & creatorName)
{
ObjectPrivsMDRow row;
PrivMgrCoreDesc corePrivs;
PrivObjectBitmap privsBitmap;
PrivObjectBitmap grantableBitmap;
corePrivs.setAllObjectGrantPrivilege(objectType,true);
privsBitmap = corePrivs.getPrivBitmap();
grantableBitmap = corePrivs.getWgoBitmap();
// Add the root grant from the system.
row.objectUID_ = objectUID_;
row.objectName_ = objectName_;
row.objectType_ = objectType;
row.granteeID_ = ownerID;
row.granteeName_ = ownerName;
row.granteeType_ = USER_GRANTEE_LIT;
row.grantorID_ = SYSTEM_USER;
row.grantorName_ = SYSTEM_AUTH_NAME;
row.grantorType_ = COM_SYSTEM_GRANTOR_LIT;
row.privsBitmap_ = privsBitmap;
row.grantableBitmap_ = grantableBitmap;
ObjectPrivsMDTable objectPrivsTable(objectTableName_,pDiags_);
PrivStatus privStatus = objectPrivsTable.insert(row);
if (privStatus != STATUS_GOOD)
return privStatus;
// If the owner and creator are the same, we are done.
// If not, this is an object being created in a private schema, and
// we need to grant privileges to the creator. If the creator is DB__ROOT,
// no need to grant privileges.
//
// This creator grant may be controlled by a CQD in the future.
if (ownerID == creatorID || creatorID == ComUser::getRootUserID() ||
ownerID == HIVE_ROLE_ID || ownerID == HBASE_ROLE_ID)
return STATUS_GOOD;
// Add a grant from the private schema owner to the creator.
row.grantorID_ = row.granteeID_;
row.grantorName_ = row.granteeName_;
row.grantorType_ = USER_GRANTOR_LIT;
row.granteeID_ = creatorID;
row.granteeName_ = creatorName;
return objectPrivsTable.insert(row);
}
// *****************************************************************************
// method: initGrantRevoke
//
// This method initializes structures needed to complete grant and revoke
// operations.
//
// It returns:
// privsToApply - the list of requested privileges to grant/revoke
// privsOfTheGrantor - privileges of the grantor to be used in later checks
//
// It also reads privileges for the object at table and column level from the
// metadata and stores the results in the class
// *****************************************************************************
PrivStatus PrivMgrPrivileges::initGrantRevoke(
const ComObjectType objectType,
const int32_t granteeID,
const std::string &grantorName,
const std::vector<PrivType> &privList,
const std::vector<ColPrivSpec> & colPrivsArray,
const bool isAllSpecified,
const bool isGOSpecified,
const bool isGrant,
PrivMgrDesc &privsToApply,
PrivMgrDesc &privsOfTheGrantor,
std::vector<int32_t> & roleIDs)
{
if (objectUID_ == 0)
{
PRIVMGR_INTERNAL_ERROR("objectUID is 0 for grant or revoke command");
return STATUS_ERROR;
}
// Generate the list of privilege descriptors that were requested
PrivStatus retcode = convertPrivsToDesc(objectType,
isAllSpecified,
(isGrant) ? isGOSpecified : true, // WGO
(isGrant) ? false : isGOSpecified, // GOF
privList,
colPrivsArray,
privsToApply);
if (retcode != STATUS_GOOD)
return retcode;
// generate the list of privileges granted to the object and store in class
if (generateObjectRowList() == STATUS_ERROR)
return STATUS_ERROR;
// generate the list of privileges granted to object columns and store in class
if (generateColumnRowList() == STATUS_ERROR)
return STATUS_ERROR;
// get column and object privileges across all grantors
bool hasManagePrivileges;
retcode = getUserPrivs(objectType, grantorID_, roleIDs, privsOfTheGrantor,
hasManagePrivileges, NULL );
if (retcode != STATUS_GOOD)
return retcode;
// get roleIDs for the grantor
retcode = getRoleIDsForUserID(grantorID_,roleIDs);
if (retcode == STATUS_ERROR)
return retcode;
// If null, the grantor has no privileges
if ( privsOfTheGrantor.isNull() )
{
std::string rolesWithPrivs;
if (getRolesToCheck(grantorID_, roleIDs, objectType, rolesWithPrivs)== STATUS_GOOD)
{
if (rolesWithPrivs.size() > 0)
{
*pDiags_ << DgSqlCode (-CAT_PRIVILEGE_NOT_GRANTED)
<< DgString0 (grantorName.c_str())
<< DgString1 (rolesWithPrivs.c_str());
return STATUS_ERROR;
}
}
*pDiags_ << DgSqlCode (-CAT_PRIVILEGE_NOT_GRANTED)
<< DgString0 (grantorName.c_str());
return STATUS_ERROR;
}
return STATUS_GOOD;
}
// *****************************************************************************
// * Method: insertPrivRowsForObject
// *
// * writes rows that add grants of privileges for an object.
// *
// * Parameters:
// *
// * <objectPrivsRows> One or more rows of grants for the object.
// *
// * Returns: PrivStatus
// *
// * STATUS_GOOD : Rows were returned
// * STATUS_NOTFOUND: No rows were returned
// * *: Unable to read privileges, see diags.
// *
// *****************************************************************************
PrivStatus PrivMgrPrivileges::insertPrivRowsForObject(
const int64_t objectUID,
const std::vector<ObjectPrivsRow> & objectPrivsRows)
{
PrivStatus retcode = STATUS_GOOD;
if (objectUID_ == 0)
{
PRIVMGR_INTERNAL_ERROR("objectUID is 0 for insertPrivRowsForObject()");
return STATUS_ERROR;
}
ObjectPrivsMDTable objectPrivsTable(objectTableName_,pDiags_);
for (int32_t i = 0; i < objectPrivsRows.size();++i)
{
ObjectPrivsMDRow row;
const ObjectPrivsRow &rowIn = objectPrivsRows[i];
char granteeTypeString[3] = {0};
char grantorTypeString[3] = {0};
row.objectUID_ = objectUID_;
row.objectName_ = rowIn.objectName;
row.objectType_ = rowIn.objectType;
row.granteeID_ = rowIn.granteeID;
row.granteeName_ = rowIn.granteeName;
CmGetComGranteeAsLit(rowIn.granteeType,granteeTypeString);
row.granteeType_ = granteeTypeString;
row.grantorID_ = rowIn.grantorID;
row.grantorName_ = rowIn.grantorName;
CmGetComGrantorAsLit(rowIn.grantorType,grantorTypeString);
row.grantorType_ = grantorTypeString;
row.privsBitmap_ = rowIn.privilegesBitmap;
row.grantableBitmap_ = rowIn.grantableBitmap;
retcode = objectPrivsTable.insert(row);
if (retcode != STATUS_GOOD)
return retcode;
}
return retcode;
}
// ****************************************************************************
// method: dealWithConstraints
//
// This method finds all the constraints associated with the table and
// determines if any are adversely affected by the privilege change.
//
// Params:
// objectUsage - the affected object
// listOfAffectedObjects - returns the list of affected objects
//
// Returns: PrivStatus
// STATUS_GOOD: No problems were encountered
// *: Errors were encountered, ComDiags area is set up
//
// ****************************************************************************
PrivStatus PrivMgrPrivileges::dealWithConstraints(
const ObjectUsage &objectUsage,
std::vector<ObjectUsage *> &listOfAffectedObjects)
{
PrivStatus retcode = STATUS_GOOD;
std::string traceMsg;
objectUsage.describe(traceMsg);
traceMsg.insert (0, "checking referencing constraints for ");
log (__FILE__, traceMsg, -1);
// RI constraints can only be defined for base tables
if (objectUsage.objectType != COM_BASE_TABLE_OBJECT)
return STATUS_GOOD;
// get the underlying tables for all RI constraints that reference the object
std::vector<ObjectReference *> objectList;
PrivMgrMDAdmin admin(trafMetadataLocation_, metadataLocation_, pDiags_);
retcode = admin.getReferencingTablesForConstraints(objectUsage, objectList);
traceMsg = "getting constraint usages: number usages found ";
traceMsg += to_string((long long int)objectList.size());
traceMsg += ", retcode is ";
traceMsg += privStatusEnumToLit(retcode);
log (__FILE__, traceMsg, -1);
if (retcode == STATUS_ERROR)
return retcode;
int32_t lastObjectOwnerID = 0;
std::vector<int32_t> roleIDs;
// objectList contains the list of objects referencing the referenced table,
// see if the requested privilege change causes an RI constraint to be invalid
for (size_t i = 0; i < objectList.size(); i++)
{
ObjectReference *pObjectRef = objectList[i];
PrivMgrDesc originalPrivs;
PrivMgrDesc currentPrivs;
pObjectRef->describe(traceMsg);
log (__FILE__, traceMsg, i);
// getRoleIDsForUserID does I/O to get information. The referencing
// list is returned by object owner to avoid rereading information for
// the same user
// At some time, we should cache user and role information
if (lastObjectOwnerID != pObjectRef->objectOwner)
{
roleIDs.clear();
retcode = getRoleIDsForUserID(pObjectRef->objectOwner,roleIDs);
if (retcode == STATUS_ERROR)
return retcode;
}
// get the summarized original and current privs for the referencing table
// current privs contains any adjustments due to the privilege change
retcode = summarizeCurrentAndOriginalPrivs(objectUsage.objectUID,
pObjectRef->objectOwner,
grantorID_,
roleIDs,
listOfAffectedObjects,
originalPrivs,
currentPrivs);
if (retcode != STATUS_GOOD)
return retcode;
PrivMgrCoreDesc thePrivs = currentPrivs.getTablePrivs();
if (!thePrivs.getPriv(REFERENCES_PRIV))
{
log (__FILE__, "User does not have reference privilege on the object", -1);
// no longer have REFERENCES privilege on the table,
// see if privileges are granted on all required columns
std::vector<ColumnReference *> summarizedColRefs;
summarizeColPrivs(*pObjectRef,
pObjectRef->objectOwner,
grantorID_,
roleIDs,
listOfAffectedObjects,
summarizedColRefs);
// check summarized privileges to see if still have priv through other privs
std::vector<ColumnReference *> neededColRefs = *pObjectRef->columnReferences;
for (size_t i = 0; i < neededColRefs.size(); i++)
{
// neededColRefs contains the list of all columns referenced by this object
// summarizedColRefs are the current privileges with the privilege change
// incorporated.
// if user still has necessary privilege through column privileges, then
// revoke can proceed
ColumnReference *neededColRef = neededColRefs[i];
for (size_t j = 0; j < summarizedColRefs.size(); j++)
{
ColumnReference *existingRef = summarizedColRefs[j];
traceMsg = "Checking if have references for col: ";
traceMsg += to_string((long long int)existingRef->columnOrdinal);
log (__FILE__, traceMsg, -1);
if (existingRef->columnOrdinal == neededColRef->columnOrdinal)
{
PrivMgrCoreDesc colPrivs = existingRef->updatedPrivs;
traceMsg = "References setting: ";
traceMsg += (colPrivs.getPriv(REFERENCES_PRIV) ? "y" : "n");
log (__FILE__, traceMsg, -1);
if (!colPrivs.getPriv(REFERENCES_PRIV))
{
std::string referencingTable;
if (!admin.getConstraintName(objectUsage.objectUID,
pObjectRef->objectUID,
neededColRef->columnOrdinal, referencingTable))
{
referencingTable = "UNKNOWN, Referencing table ID is ";
referencingTable += UIDToString(pObjectRef->objectUID );
}
*pDiags_ << DgSqlCode (-CAT_DEPENDENT_OBJECTS_EXIST)
<< DgString0 (referencingTable.c_str());
retcode = STATUS_ERROR;
}
break;
}
}
}
// remove list of summarized columns
while (!summarizedColRefs.empty())
delete summarizedColRefs.back(), summarizedColRefs.pop_back();
}
}
return retcode;
}
// ****************************************************************************
// method: dealWithUdrs
//
// This method finds all the udrs associated with the library and
// determines if any are adversely affected by the privilege change.
//
// Params:
// objectUsage - the affected object
// listOfAffectedObjects - returns the list of affected objects
//
// Returns: PrivStatus
// STATUS_GOOD: No problems were encountered
// *: Errors were encountered, ComDiags area is set up
//
// ****************************************************************************
PrivStatus PrivMgrPrivileges::dealWithUdrs(
const ObjectUsage &objectUsage,
std::vector<ObjectUsage *> &listOfAffectedObjects)
{
PrivStatus retcode = STATUS_GOOD;
// udrs (functions and procedures) can only be defined for in libraries
if (objectUsage.objectType != COM_LIBRARY_OBJECT)
return STATUS_GOOD;
std::string traceMsg;
objectUsage.describe(traceMsg);
traceMsg.insert (0, "checking referencing routines for ");
log (__FILE__, traceMsg, -1);
// get the udrs that reference the library for the grantee
std::vector<ObjectReference *> objectList;
PrivMgrMDAdmin admin(trafMetadataLocation_, metadataLocation_, pDiags_);
retcode = admin.getUdrsThatReferenceLibrary(objectUsage, objectList);
traceMsg = "getting routine usages: number usages found ";
traceMsg += to_string((long long int)objectList.size());
traceMsg += ", retcode is ";
traceMsg += privStatusEnumToLit(retcode);
log (__FILE__, traceMsg, -1);
if (retcode == STATUS_ERROR)
return retcode;
// objectList contain ObjectReferences for all udrs that reference the
// ObjectUsage (object losing privilege) through a library
PrivMgrDesc originalPrivs;
PrivMgrDesc currentPrivs;
if (objectList.size() > 0)
{
std::vector<int32_t> roleIDs;
retcode = getRoleIDsForUserID(objectUsage.granteeID,roleIDs);
if (retcode == STATUS_ERROR)
return retcode;
// if the grantee owns any udrs, get the summarized original and current
// privs for the library
// current privs contains any adjustments
retcode = summarizeCurrentAndOriginalPrivs(objectUsage.objectUID,
objectUsage.granteeID,
grantorID_,
roleIDs,
listOfAffectedObjects,
originalPrivs,
currentPrivs);
if (retcode != STATUS_GOOD)
return retcode;
// If the udr can no longer be created due to lack of USAGE privilege,
// return a dependency error.
PrivMgrCoreDesc thePrivs = objectUsage.updatedPrivs.getTablePrivs();
if (!thePrivs.getPriv(USAGE_PRIV))
{
// There could be multiple udrs, just pick the first one in the list
// for the error message.
ObjectReference *pObjectRef = objectList[0];
*pDiags_ << DgSqlCode (-CAT_DEPENDENT_OBJECTS_EXIST)
<< DgString0 (pObjectRef->objectName.c_str());
return STATUS_ERROR;
}
}
return STATUS_GOOD;
}
// ****************************************************************************
// method: dealWithViews
//
// This method finds all the views that referenced the object.
// This method recursively calls itself to find other views referenced in the
// tree of referencing views
//
// Params:
// objectUsage - the affected object
// command - type of command - grant, revoke restrict, revoke cascade
// listOfAffectedObjects - returns the list of affected objects
//
// Returns: PrivStatus
// STATUS_GOOD: No problems were encountered
// *: Errors were encountered, ComDiags area is set up
//
// In the future, we want to cache the lists of objects instead of going to the
// metadata everytime.
// ****************************************************************************
PrivStatus PrivMgrPrivileges::dealWithViews(
const ObjectUsage &objectUsage,
const PrivCommand command,
const int32_t grantorID,
std::vector<ObjectUsage *> &listOfAffectedObjects)
{
PrivStatus retcode = STATUS_GOOD;
std::string traceMsg;
objectUsage.describe(traceMsg);
traceMsg.insert (0, "checking referencing views for ");
log (__FILE__, traceMsg, -1);
// Get any views that referenced this object to see if the privilege changes
// should be propagated
std::vector<ViewUsage> viewUsages;
PrivMgrMDAdmin admin(trafMetadataLocation_, metadataLocation_, pDiags_);
retcode = admin.getViewsThatReferenceObject(objectUsage, viewUsages);
traceMsg = "getting view usages: number usages found ";
traceMsg += to_string((long long int)viewUsages.size());
traceMsg += ", retcode is ";
traceMsg += privStatusEnumToLit(retcode);
log (__FILE__, traceMsg, -1);
if (retcode == STATUS_NOTFOUND)
return STATUS_GOOD;
if (retcode != STATUS_GOOD && retcode != STATUS_WARNING)
return retcode;
// for each entry in the viewUsages list calculate the changed privileges
// if privileges change, add viewUsage to listOfAffectedObjects
for (size_t i = 0; i < viewUsages.size(); i++)
{
ViewUsage viewUsage = viewUsages[i];
viewUsage.describe(traceMsg);
log (__FILE__, traceMsg, i);
// gatherViewPrivileges recreates privileges for the view based on changes
// requested by the current grant/revoke request
// Updated priv descriptors are stored in the viewUsage structure.
retcode = gatherViewPrivileges(viewUsage, command, grantorID, listOfAffectedObjects);
traceMsg = "gathered view privs: retcode is ";
traceMsg += privStatusEnumToLit(retcode);
log (__FILE__, traceMsg, -1);
if (retcode != STATUS_GOOD && retcode != STATUS_WARNING)
return retcode;
// check to see if privileges changed
if (viewUsage.originalPrivs == viewUsage.updatedPrivs)
continue;
else
{
// This view privs have been changed by the grant/revoke request
// However, only INSERT, DELETE, and UPDATE privs can be propagated
// If the view is not updatable or insertable then, we are done with
// this viewUsage
if (viewUsage.isUpdatable || viewUsage.isInsertable)
{
// Add viewUsage to list of affected objects
ObjectUsage *pUsage = new (ObjectUsage);
pUsage->objectUID = viewUsage.viewUID;
pUsage->granteeID = viewUsage.viewOwner;
pUsage->grantorIsSystem = true;
pUsage->objectName = viewUsage.viewName;
pUsage->objectType = COM_VIEW_OBJECT;
pUsage->originalPrivs = viewUsage.originalPrivs;
pUsage->updatedPrivs = viewUsage.updatedPrivs;
listOfAffectedObjects.push_back(pUsage);
traceMsg = "adding new objectUsage for ";
pUsage->describe(traceMsg);
log (__FILE__, traceMsg, i);
#if 0
// When cascade is supported, the list of down stream views must be
// included in the list of affected objects.
// Also, need to understand ANSI SQL rules for propagating view privs,
// that is, should down stream views be updated if it parent view
// privs are changed and the parent has WGO specified.
// get list of grantee ID's that have been granted privileges on the
// current view.
std::set<int32_t> granteeList;
if (getGranteesForViewUsage(viewUsage, granteeList) == STATUS_ERROR)
{
PRIVMGR_INTERNAL_ERROR("Error while getting grantees for down stream views");
return STATUS_ERROR;
}
// Call dealWithViews to see if the down stream views should be adjusted.
for (std::set<int32_t>::iterator it = granteeList.begin(); it!= granteeList.end(); ++it)
{
pUsage->granteeID = *it;
retcode = dealWithViews(*pUsage, command, viewUsage.viewOwner, listOfAffectedObjects);
if (retcode != STATUS_GOOD && retcode != STATUS_WARNING)
return retcode;
}
pUsage->granteeID = viewUsage.viewOwner;
#endif
} // updatable views
} // view privs changed
} // list of view usages
return STATUS_GOOD;
}
// ----------------------------------------------------------------------------
// method: gatherViewColUsages
//
// This method gathers the view-col <=> referenced-col usages and creates a
// list of ComViewColUsage's for the referenced object. Each ComViewColUsage
// is identified the view column number, and the related UID and column number
// of the referenced object.
//
// parameters:
// objectRef - description of the referenced object
// viewUsage - description of the view
// viewColUsages - list of view column, referenced column usages
//
// Returns: PrivStatus
//
// STATUS_GOOD: Operation successful
// *: Unable to gather usages, see diags.
//
// ----------------------------------------------------------------------------
PrivStatus PrivMgrPrivileges::gatherViewColUsages(
ObjectReference *objectRef,
ViewUsage &viewUsage,
std::vector<ComViewColUsage> &viewColUsages)
{
std::string traceMsg;
PrivStatus retcode;
PrivMgrMDAdmin admin(trafMetadataLocation_, metadataLocation_, pDiags_);
// Get columns for referenced object if they are not already present
if (objectRef->columnReferences == NULL)
{
retcode = admin.getColumnReferences(objectRef);
if (objectRef->columnReferences)
{
traceMsg += "getting column references: number references found ";
traceMsg += to_string((long long int)objectRef->columnReferences->size());
traceMsg += ", ";
}
traceMsg += "retcode is ";
traceMsg += privStatusEnumToLit(retcode);
log (__FILE__, traceMsg, -1);
if (retcode == STATUS_ERROR)
return retcode;
}
// Extract view <=> object column relationship from the TEXT table
// and add it to the viewUsage
if (viewUsage.viewColUsagesStr.empty())
{
retcode = admin.getViewColUsages(viewUsage);
traceMsg = "getting view column usages";
traceMsg += ", retcode is ";
traceMsg += privStatusEnumToLit(retcode);
log (__FILE__, traceMsg, -1);
if (retcode != STATUS_GOOD)
return retcode;
}
// Setup the view column to referenced column relationship
char * beginStr = (char *)viewUsage.viewColUsagesStr.c_str();
char * endStr = strchr(beginStr, ';');
while (endStr != NULL)
{
ComViewColUsage colUsage;
std::string currentUsage(beginStr, endStr - beginStr + 1);
colUsage.unpackUsage (currentUsage.c_str());
viewColUsages.push_back(colUsage);
beginStr = endStr+1;
endStr = strchr(beginStr, ';');
}
return STATUS_GOOD;
}
// ----------------------------------------------------------------------------
// method: gatherViewPrivileges
//
// This method gathers privileges for the view both the original and current
//
// parameters:
// viewUsage - description of the view
// listOfAffectedObjects - list of changed privileges so far
//
// Returns: PrivStatus
//
// STATUS_GOOD: Privileges were gathered
// *: Unable to gather privileges, see diags.
//
// ----------------------------------------------------------------------------
PrivStatus PrivMgrPrivileges::gatherViewPrivileges(
ViewUsage &viewUsage,
const PrivCommand command,
const int32_t grantorID,
const std::vector<ObjectUsage *> listOfAffectedObjects)
{
PrivStatus retcode = STATUS_GOOD;
std::string traceMsg;
// initialize summarized descriptors and set all applicable privileges
// TBD: if view is not updatable, should initialize correctly.
// views have same privileges as tables
bool setWGOtrue = true;
PrivMgrDesc summarizedOriginalPrivs;
summarizedOriginalPrivs.setAllTableGrantPrivileges(setWGOtrue);
PrivMgrDesc summarizedCurrentPrivs;
summarizedCurrentPrivs.setAllTableGrantPrivileges(setWGOtrue);
// Get list of objects referenced by the view
std::vector<ObjectReference *> objectList;
PrivMgrMDAdmin admin(trafMetadataLocation_, metadataLocation_, pDiags_);
retcode = admin.getObjectsThatViewReferences(viewUsage, objectList);
traceMsg += "getting object references: number references found ";
traceMsg += to_string((long long int)objectList.size());
traceMsg += ", retcode is ";
traceMsg += privStatusEnumToLit(retcode);
log (__FILE__, traceMsg, -1);
if (retcode == STATUS_ERROR)
return retcode;
// For each referenced object, summarize the original and current
// privileges
PrivMgrDesc originalPrivs;
PrivMgrDesc currentPrivs;
int32_t lastObjectOwnerID = 0;
std::vector<int32_t> roleIDs;
retcode = getRoleIDsForUserID(viewUsage.viewOwner,roleIDs);
if (retcode == STATUS_ERROR)
return retcode;
// First gather privileges on the object
for (size_t i = 0; i < objectList.size(); i++)
{
ObjectReference *pObjectRef = objectList[i];
pObjectRef->describe(traceMsg);
log (__FILE__, traceMsg, i);
// get the summarized original and current privs for the
// referenced object that have been granted to the view owner
// listOfAffectedObjects contain the privilege adjustments needed
// to generate the current privs
retcode = summarizeCurrentAndOriginalPrivs(pObjectRef->objectUID,
viewUsage.viewOwner,
grantorID,
roleIDs,
listOfAffectedObjects,
originalPrivs,
currentPrivs);
if (retcode != STATUS_GOOD)
return retcode;
// If the referenced object is a sequence generator, then the grantee
// must still have the USAGE_PRIV. The USAGE_PRIV is not a column
// level privilege so no column level check is necessary.
if (isRevokeCommand(command))
{
if (pObjectRef->objectType == COM_SEQUENCE_GENERATOR_OBJECT)
{
PrivMgrCoreDesc thePrivs = currentPrivs.getTablePrivs();
if (!thePrivs.getPriv(USAGE_PRIV))
{
*pDiags_ << DgSqlCode (-CAT_DEPENDENT_OBJECTS_EXIST)
<< DgString0 (viewUsage.viewName.c_str());
return STATUS_ERROR;
}
}
}
// "and" the returned privilege to the summarized privileges
// for all objects
summarizedOriginalPrivs.intersectionOfPrivs(originalPrivs);
summarizedCurrentPrivs.intersectionOfPrivs(currentPrivs);
// reset to prepare for next object
originalPrivs.resetTablePrivs();
currentPrivs.resetTablePrivs();
}
// If view has all grantable col privs already, no need to check further
bool checkCols = false;
PrivMgrCoreDesc thePrivs = summarizedCurrentPrivs.getTablePrivs();
for (size_t i = FIRST_DML_COL_PRIV; i <= LAST_DML_COL_PRIV; i++ )
{
PrivType privType = PrivType(i);
if (thePrivs.getPriv(privType) && thePrivs.getWgo(privType))
continue;
checkCols = true;
break;
}
// No need to check col privs, return with summarized privs
if (!checkCols)
{
// Update view usage with summarized privileges
viewUsage.originalPrivs = summarizedOriginalPrivs;
viewUsage.updatedPrivs = summarizedCurrentPrivs;
return STATUS_GOOD;
}
// Turn on bits to prepare for intersecting with object privileges
originalPrivs.setAllTableGrantPrivileges(setWGOtrue);
currentPrivs.setAllTableGrantPrivileges(setWGOtrue);
std::vector<ColumnReference *> summarizedColRefs;
// Gather column privileges on all objects referencing the view.
// for grants, a view might gain privs
// for revokes, a view might lose privs
// For example:
// as user1:
// create table sch1.t1 (c1 int, c2 int, ....);
// grant select on sch1.t1 to user2;
// grant insert (c1) on sch1.t1 to user2
// as user2:
// create view sch2.v1 as select c1 from sch1.t1;
// view sch2.v1 gains the insert privilege since all columns that
// sch2.v1 references have granted user2 the insert privilege.
for (size_t i = 0; i < objectList.size(); i++)
{
ObjectReference *pObjectRef = objectList[i];
// gather the view-col <=> referenced-col usages
std::vector <ComViewColUsage> viewColUsages;
retcode = gatherViewColUsages(pObjectRef, viewUsage, viewColUsages);
if (retcode == STATUS_ERROR)
return retcode;
// The view-col <=> referenced_col relationship is not found
// No need to proceed further.
// If this is a grant of a column privilege, return an error
// User needs to drop and recreate view
// The view-col <=> referenced-col usages are only being started in
// metadata after column privileges are officially supported. Any views
// create before this time, do not have this information, so column privs
// either do not exist (revoke) or cannot be added (grant). The view needs
// to be dropped and recreated (or add a fixup procedure).
if (retcode == STATUS_NOTFOUND)
{
if (command == GRANT_COLUMN)
{
*pDiags_ << DgSqlCode (-CAT_COLUMN_PRIVILEGE_NOT_ALLOWED)
<< DgTableName (viewUsage.viewName.c_str());
return STATUS_ERROR;
}
return STATUS_GOOD;
}
// gather the updated summarized column privileges on the referenced object
summarizeColPrivs(*pObjectRef,
viewUsage.viewOwner,
grantorID,
roleIDs,
listOfAffectedObjects,
summarizedColRefs);
// For each view column, get the corresponding referenced column priv
for (size_t j = 0; j < viewColUsages.size(); j++)
{
ComViewColUsage colUsage = viewColUsages[j];
// See if the referenced object contains the associated view column
if (colUsage.getRefdUID() != pObjectRef->objectUID)
continue;
// Get the referenced column, if NULL then something is wrong
ColumnReference *neededColRef = pObjectRef->find(colUsage.getRefdColNumber());
if (neededColRef == NULL)
{
PRIVMGR_INTERNAL_ERROR("View column to referenced column relationship wrong");
return STATUS_ERROR;
}
// Find and update the current bitmaps for column
for (size_t k = 0; k < summarizedColRefs.size(); k++)
{
ColumnReference *existingRef = summarizedColRefs[k];
if (existingRef->columnOrdinal == neededColRef->columnOrdinal)
{
originalPrivs.intersectionOfPrivs(existingRef->originalPrivs);
currentPrivs.intersectionOfPrivs(existingRef->updatedPrivs);
break;
}
}
}
}
// Union or "or" the returned privileges to the summarized privileges
// for all columns. The privilege is set in currentPrivs only if all
// columns in the view have the privilege.
summarizedOriginalPrivs.unionOfPrivs(originalPrivs);
summarizedCurrentPrivs.unionOfPrivs(currentPrivs);
// If user no longer has select privilege on referenced object
// returns an error
// When cascade is supported, then referenced objects will be removed
if (isRevokeCommand(command))
{
if (!summarizedCurrentPrivs.getTablePrivs().getPriv(SELECT_PRIV))
{
*pDiags_ << DgSqlCode (-CAT_DEPENDENT_OBJECTS_EXIST)
<< DgString0 (viewUsage.viewName.c_str());
return STATUS_ERROR;
}
}
// If view is not updatable or insertable, turn off privs in bitmaps
if (!viewUsage.isUpdatable)
{
summarizedCurrentPrivs.getTablePrivs().setPriv(UPDATE_PRIV,false);
summarizedCurrentPrivs.getTablePrivs().setPriv(UPDATE_PRIV, false);
summarizedCurrentPrivs.getTablePrivs().setPriv(DELETE_PRIV,false);
summarizedCurrentPrivs.getTablePrivs().setPriv(DELETE_PRIV, false);
}
if (!viewUsage.isInsertable)
{
summarizedCurrentPrivs.getTablePrivs().setPriv(INSERT_PRIV,false);
summarizedCurrentPrivs.getTablePrivs().setPriv(INSERT_PRIV, false);
}
// Update view usage with summarized privileges
viewUsage.originalPrivs = summarizedOriginalPrivs;
viewUsage.updatedPrivs = summarizedCurrentPrivs;
return STATUS_GOOD;
}
// ****************************************************************************
// method: generateColumnRowList
//
// generate the list of privileges granted to columns of the object and
// store in columnRowList_ class member
//
// Returns:
// STATUS_GOOD - list of rows was generated
// STATUS_NOTFOUND - no column privileges were found
// STATUS_ERROR - the diags area is populated with any errors
// ****************************************************************************
PrivStatus PrivMgrPrivileges::generateColumnRowList()
{
// If columnRowList_ already allocated, just return
if (columnRowList_.size() > 0)
return STATUS_GOOD;
PrivStatus privStatus = getColumnRowList(objectUID_, columnRowList_);
if (privStatus == STATUS_ERROR)
return privStatus;
return STATUS_GOOD;
}
// ****************************************************************************
// method: getColumnRowList
//
// generate the list of privileges granted to the passed in objectUID and
// returns in the columnRowList parameter
//
// The list is ordered by grantor/grantee/column_number
//
// Returns:
// STATUS_GOOD - list of rows was generated
// STATUS_NOTFOUND - in most cases, there should be at least one row in the
// OBJECT_PRIVILEGES table. But there is at least one case
// where this is not true - trying to get privilege info
// for indexes when using the table (index_table) syntax.
// STATUS_ERROR - the diags area is populated with any errors
// ****************************************************************************
PrivStatus PrivMgrPrivileges::getColumnRowList(
const int64_t objectUID,
std::vector<PrivMgrMDRow *> &columnRowList)
{
std::string whereClause ("where object_uid = ");
whereClause += UIDToString(objectUID);
std::string orderByClause (" order by grantor_id, grantee_id, column_number ");
ColumnPrivsMDTable columnPrivsTable(columnTableName_,pDiags_);
PrivStatus privStatus =
columnPrivsTable.selectWhere(whereClause, orderByClause, columnRowList);
std::string traceMsg ("getting column privileges, number privileges is ");
traceMsg += to_string((long long int)columnRowList.size());
log (__FILE__, traceMsg, -1);
for (size_t i = 0; i < columnRowList.size(); i++)
{
ColumnPrivsMDRow privRow = static_cast<ColumnPrivsMDRow &> (*columnRowList[i]);
privRow.describeRow(traceMsg);
log (__FILE__, traceMsg, i);
}
return privStatus;
}
// ****************************************************************************
// method: generateObjectRowList
//
// generate the list of privileges granted to the object and
// store in objectRowList_ class member
//
// Returns:
// STATUS_GOOD - list of rows was generated
// STATUS_NOTFOUND - in most cases, there should be at least one row in the
// OBJECT_PRIVILEGES table. But there is at least one case
// where this is not true - trying to get privilege info
// for indexes when using the table (index_table) syntax.
// STATUS_ERROR - the diags area is populated with any errors
// ****************************************************************************
PrivStatus PrivMgrPrivileges::generateObjectRowList()
{
// If objectRowList_ already allocated, just return
if (objectRowList_.size() > 0)
return STATUS_GOOD;
PrivStatus privStatus = getObjectRowList(objectUID_, objectRowList_);
if (privStatus == STATUS_ERROR)
return privStatus;
return STATUS_GOOD;
}
// ****************************************************************************
// method: getObjectRowList
//
// generate the list of privileges granted to the passed in objectUID and
// returns in the objectRowList parameter
//
// The list is ordered by grantor/grantee
//
// Returns:
// STATUS_GOOD - list of rows was generated
// STATUS_NOTFOUND - in most cases, there should be at least one row in the
// OBJECT_PRIVILEGES table. But there is at least one case
// where this is not true - trying to get privilege info
// for indexes when using the table (index_table) syntax.
// STATUS_ERROR - the diags area is populated with any errors
// ****************************************************************************
PrivStatus PrivMgrPrivileges::getObjectRowList(
const int64_t objectUID,
std::vector<PrivMgrMDRow *> &objectRowList)
{
std::string whereClause ("where object_uid = ");
whereClause += UIDToString(objectUID);
std::string orderByClause(" order by grantor_id, grantee_id ");
ObjectPrivsMDTable objectPrivsTable(objectTableName_,pDiags_);
PrivStatus privStatus =
objectPrivsTable.selectWhere(whereClause, orderByClause, objectRowList);
if (privStatus == STATUS_ERROR)
return privStatus;
std::string traceMsg ("getting object privileges, number privleges is ");
traceMsg += to_string((long long int)objectRowList.size());
log (__FILE__, traceMsg, -1);
for (size_t i = 0; i < objectRowList.size(); i++)
{
ObjectPrivsMDRow privRow = static_cast<ObjectPrivsMDRow &> (*objectRowList[i]);
privRow.describeRow(traceMsg);
log (__FILE__, traceMsg, i);
}
return STATUS_GOOD;
}
// ****************************************************************************
// method: getAffectedObjects
//
// This method adds the current object to the listOfAffectedObjects and then
// looks for dependent objects such as constraints and views that will be
// affected by the privilege change.
//
// Params:
// objectUsage - the affected object
// command - GRANT or REVOKE RESTRICT or REVOKE CASCADE
// listOfAffectedObjects - returns the list of affected objects
// ****************************************************************************
PrivStatus PrivMgrPrivileges::getAffectedObjects(
const ObjectUsage &objectUsage,
const PrivCommand command,
std::vector<ObjectUsage *> &listOfAffectedObjects)
{
PrivStatus retcode = STATUS_GOOD;
std::string traceMsg;
// found an object whose privileges need to be updated
ObjectUsage *pUsage = new (ObjectUsage);
pUsage->objectUID = objectUsage.objectUID;
pUsage->granteeID = objectUsage.granteeID;
pUsage->grantorIsSystem = objectUsage.grantorIsSystem;
pUsage->objectName = objectUsage.objectName;
pUsage->objectType = objectUsage.objectType;
pUsage->originalPrivs = objectUsage.originalPrivs;
pUsage->updatedPrivs = objectUsage.updatedPrivs;
pUsage->copyColumnReferences(objectUsage.columnReferences);
listOfAffectedObjects.push_back(pUsage);
// Find list of affected constraints
if (isRevokeCommand(command))
{
// TBD optimization: if no "references" privilege has been revoked, skip
retcode = dealWithConstraints (objectUsage, listOfAffectedObjects);
if (retcode == STATUS_ERROR)
return retcode;
// TBD optimization: if no "execute" privilege has been revoked, skip
retcode = dealWithUdrs (objectUsage, listOfAffectedObjects);
if (retcode != STATUS_GOOD && retcode != STATUS_WARNING)
return retcode;
}
// Find list of affected views
retcode = dealWithViews (objectUsage, command, grantorID_, listOfAffectedObjects);
if (retcode != STATUS_GOOD && retcode != STATUS_WARNING)
return retcode;
return STATUS_GOOD;
}
// ----------------------------------------------------------------------------
// method: getGrantedPrivs
//
// This method searches the list of object privs to get information for the
// object, grantor, and grantee.
//
// input: granteeID
// output: a row from the object_privileges table describing privilege details
//
// Returns: PrivStatus
//
// STATUS_GOOD: row was found (and returned)
// STATUS_NOTFOUND: no privileges have been granted
// ----------------------------------------------------------------------------
PrivStatus PrivMgrPrivileges::getGrantedPrivs(
const int32_t granteeID,
PrivMgrMDRow &rowOut)
{
ObjectPrivsMDRow & row = static_cast<ObjectPrivsMDRow &>(rowOut);
for (size_t i = 0; i < objectRowList_.size(); i++)
{
ObjectPrivsMDRow privRow = static_cast<ObjectPrivsMDRow &> (*objectRowList_[i]);
if (privRow.grantorID_ == grantorID_ && privRow.granteeID_ == granteeID)
{
row = privRow;
return STATUS_GOOD;
}
}
return STATUS_NOTFOUND;
}
// ----------------------------------------------------------------------------
// method: getGranteesForViewUsage
//
// returns the list of grantees that have been granted privileges by the view
// owner
//
// input: viewUsage
// output: a unique list of grantees
//
// Returns: PrivStatus
//
// STATUS_GOOD: list was generated
// STATUS_ERROR: unexpected error occurred
// ----------------------------------------------------------------------------
PrivStatus PrivMgrPrivileges::getGranteesForViewUsage (
const ViewUsage &viewUsage,
std::set<int32_t> &granteeList)
{
PrivStatus privStatus = STATUS_GOOD;
std::string whereClause ("where object_uid = ");
whereClause += UIDToString(viewUsage.viewUID);
whereClause += " and grantor_id <> -2 ";
std::string orderByClause("order by grantee_id");
std::vector<PrivMgrMDRow *> rowList;
// get list of grantees from object_privileges
ObjectPrivsMDTable objectPrivsTable(objectTableName_,pDiags_);
privStatus = objectPrivsTable.selectWhere(whereClause,orderByClause,rowList);
if (privStatus == STATUS_ERROR)
{
deleteRowList(rowList);
return privStatus;
}
for (size_t i = 0; i < rowList.size(); i++)
{
ObjectPrivsMDRow &currentRow = static_cast<ObjectPrivsMDRow &> (*rowList[i]);
granteeList.insert(currentRow.granteeID_);
}
deleteRowList(rowList);
// get list of grantees for column_privileges
ColumnPrivsMDTable columnPrivsTable(columnTableName_,pDiags_);
privStatus = columnPrivsTable.selectWhere(whereClause, orderByClause, rowList);
if (privStatus == STATUS_ERROR)
{
deleteRowList(rowList);
return privStatus;
}
for (size_t i = 0; i < rowList.size(); i++)
{
ColumnPrivsMDRow &currentRow = static_cast<ColumnPrivsMDRow &> (*rowList[i]);
granteeList.insert(currentRow.granteeID_);
}
deleteRowList(rowList);
return STATUS_GOOD;
}
// ----------------------------------------------------------------------------
// method: getGrantorDetailsForObject
//
// returns the effective grantor ID and grantor name for grant and revoke
// object statements
//
// Input:
// isGrantedBySpecified - true if grant request included a GRANTED BY clause
// grantedByName - name specified in GRANTED BY clause
// objectOwner - owner of object that is the subject for the grant or revoke
//
// Output:
// effectiveGrantorID - the ID to use for grant and revoke
// effectiveGrantorName - the name to use for grant and revoke
//
// returns PrivStatus with the results of the operation. The diags area
// contains error details.
// ----------------------------------------------------------------------------
PrivStatus PrivMgrPrivileges::getGrantorDetailsForObject(
const bool isGrantedBySpecified,
const std::string grantedByName,
const int_32 objectOwner,
int_32 &effectiveGrantorID,
std::string &effectiveGrantorName)
{
int_32 currentUser = ComUser::getCurrentUser();
short retcode = 0;
if (!isGrantedBySpecified)
{
// If the user is DB__ROOT, a grant or revoke operation is implicitly on
// behalf of the object owner. Likewise, if a user has been granted the
// MANAGE_PRIVILEGES component-level privilege they can grant on
// behalf of the owner implicitly. Otherwise, the grantor is the user.
if (!ComUser::isRootUserID())
{
PrivMgrComponentPrivileges componentPrivileges(metadataLocation_,pDiags_);
if (!componentPrivileges.hasSQLPriv(currentUser,SQLOperation::MANAGE_PRIVILEGES,
true))
{
effectiveGrantorName = ComUser::getCurrentUsername();
effectiveGrantorID = currentUser;
return STATUS_GOOD;
}
}
// User is DB__ROOT. Get the effective grantor name.
char authName[MAX_USERNAME_LEN+1];
Int32 actualLen = 0;
retcode = ComUser::getAuthNameFromAuthID(objectOwner,authName,
MAX_USERNAME_LEN+1,actualLen);
if (retcode != FEOK)
{
*pDiags_ << DgSqlCode(-20235)
<< DgInt0(retcode)
<< DgInt1(objectOwner);
return STATUS_ERROR;
}
effectiveGrantorID = objectOwner;
effectiveGrantorName = authName;
return STATUS_GOOD;
}
// GRANTED BY was specified, first see if authorization name is valid. Then
// determine if user has authority to use the clause.
// Get the grantor ID from the grantorName
retcode = ComUser::getAuthIDFromAuthName(grantedByName.c_str(),effectiveGrantorID);
if (retcode == FENOTFOUND)
{
*pDiags_ << DgSqlCode(-CAT_AUTHID_DOES_NOT_EXIST_ERROR)
<< DgString0(grantedByName.c_str());
return STATUS_ERROR;
}
if (retcode != FEOK)
{
*pDiags_ << DgSqlCode(-20235)
<< DgInt0(retcode)
<< DgInt1(objectOwner);
return STATUS_ERROR;
}
effectiveGrantorName = grantedByName;
// Name exists, does user have authority?
//
// GRANTED BY is allowed if any of the following are true:
//
// 1) The user is DB__ROOT.
// 2) The user is owner of the object.
// 3) The user has been granted the MANAGE_PRIVILEGES component-level privilege.
// 4) The grantor is a role and the user has been granted the role.
if (ComUser::isRootUserID() || currentUser == objectOwner)
return STATUS_GOOD;
PrivMgrComponentPrivileges componentPrivileges(metadataLocation_,pDiags_);
if (componentPrivileges.hasSQLPriv(currentUser,SQLOperation::MANAGE_PRIVILEGES,
true))
return STATUS_GOOD;
// If the grantor is not a role, user does not have authority.
if (!isRoleID(effectiveGrantorID))
{
*pDiags_ << DgSqlCode(-CAT_NOT_AUTHORIZED);
return STATUS_ERROR;
}
// Role specified in BY clause must be granted to the current user for user
// to have authority.
PrivMgrRoles roles(trafMetadataLocation_,metadataLocation_,pDiags_);
if (roles.hasRole(currentUser,effectiveGrantorID))
return STATUS_GOOD;
*pDiags_ << DgSqlCode(-CAT_NOT_AUTHORIZED);
return STATUS_ERROR;
}
// *****************************************************************************
// * Method: revokeColumnPriv
// *
// * Adds or updates a row in the COLUMN_PRIVILEGES table.
// *
// * Parameters:
// *
// * <objectType> is the type of the subject object.
// * <granteeID> is the unique identifier for the grantee
// * <granteeName> is the name of the grantee (upper cased)
// * <grantorName> is the name of the grantor (upper cased)
// * <colPrivsArray> is the list of columns and privileges to grant
// * <isWGOSpecified> is true then also allow the grantee to grant the set
// * of privileges to other grantees
// *
// * Returns: PrivStatus
// *
// * STATUS_GOOD: Privileges were revoked
// * *: Unable to revoke privileges, see diags.
// *
// *****************************************************************************
PrivStatus PrivMgrPrivileges::revokeColumnPriv(
const ComObjectType objectType,
const int32_t granteeID,
const std::string & granteeName,
const std::string & grantorName,
const PrivMgrDesc & privsToRevoke,
const bool isWGOSpecified)
{
PrivStatus privStatus = STATUS_GOOD;
log (__FILE__, "checking column privileges", -1);
NAList<PrivMgrCoreDesc> colPrivsToRevoke = privsToRevoke.getColumnPrivs();
// Get existing column grants from grantor to the specified grantee.
NAList<PrivMgrCoreDesc> grantedColPrivs(STMTHEAP);
getColRowsForGranteeGrantor(columnRowList_,
granteeID,grantorID_,
grantedColPrivs);
// set up the object usage
ObjectUsage objectUsage;
objectUsage.objectUID = objectUID_;
objectUsage.granteeID = granteeID;
objectUsage.objectName = objectName_;
objectUsage.objectType = objectType;
// Create list of ColumnReferences
objectUsage.columnReferences = new std::vector<ColumnReference *>;
for (size_t i = 0; i < colPrivsToRevoke.entries(); i++)
{
PrivMgrCoreDesc &colPrivToRevoke = colPrivsToRevoke[i];
PrivMgrCoreDesc *grantedColPriv = findColumnEntry(grantedColPrivs, colPrivToRevoke.getColumnOrdinal());
if (grantedColPriv)
{
if (colPrivToRevoke.anyNotSet(*grantedColPriv))
{
// sanity check -> verify that privileges to revoke actually are set
// in the granted list
for (size_t p = FIRST_DML_COL_PRIV; p <= LAST_DML_COL_PRIV; p++ )
{
PrivType type = (PrivType)p;
// If trying to revoke a privilege that is not granted or
// if trying to revoke grant option that is not granted, report it
//if ((colPrivToRevoke.getPriv(type) && !grantedColPriv->getPriv(type)) ||
// (!colPrivToRevoke.getPriv(type) && colPrivToRevoke.getWgo(type) && !grantedColPriv->getWgo(type)))
bool printWarning = false;
bool printWgo = false;
if (colPrivToRevoke.getPriv(type))
{
if ( !grantedColPriv->getPriv(type))
printWarning = true;
}
else
{
if (colPrivToRevoke.getWgo(type) && !grantedColPriv->getWgo(type))
{
printWarning = true;
printWgo = true;
}
}
if (printWarning)
{
char buf[1000];
sprintf(buf, "%s %s (columm number %d) on %s",
PrivMgrUserPrivs::convertPrivTypeToLiteral(type).c_str(),
(colPrivToRevoke.getWgo(type)) ? "WITH GRANT OPTION" : "",
colPrivToRevoke.getColumnOrdinal(), objectName_.c_str());
*pDiags_ << DgSqlCode(CAT_GRANT_NOT_FOUND)
<< DgString0(buf)
<< DgString1(grantorName.c_str())
<< DgString2(granteeName.c_str());
}
}
}
ColumnReference *adjustedCol = new ColumnReference;
adjustedCol->columnOrdinal = colPrivToRevoke.getColumnOrdinal();
adjustedCol->originalPrivs = *grantedColPriv;
PrivMgrCoreDesc adjustedPrivs = *grantedColPriv;
adjustedPrivs.AndNot(colPrivToRevoke);
adjustedCol->updatedPrivs = adjustedPrivs;
objectUsage.columnReferences->push_back(adjustedCol);
}
else
{
// report errors for any missing grants
for (size_t p = FIRST_DML_COL_PRIV; p <= LAST_DML_COL_PRIV; p++ )
{
// If trying to revoke a privilege that is not granted or
// if trying to revoke grant option that is not granted, report it
if (colPrivToRevoke.getPriv((PrivType)p) || colPrivToRevoke.getWgo((PrivType)p))
{
char buf[1000];
sprintf(buf, "%s %s (columm number %d) on %s",
PrivMgrUserPrivs::convertPrivTypeToLiteral((PrivType)p).c_str(),
(colPrivToRevoke.getWgo((PrivType)p)) ? "WITH GRANT OPTION" : "",
colPrivToRevoke.getColumnOrdinal(), objectName_.c_str());
*pDiags_ << DgSqlCode(CAT_GRANT_NOT_FOUND)
<< DgString0(buf)
<< DgString1(grantorName.c_str())
<< DgString2(granteeName.c_str());
}
}
}
}
if (objectUsage.columnReferences->size() == 0)
return STATUS_GOOD;
// Get privileges on the object for grantor/grantee
ObjectPrivsMDRow objRow;
privStatus = getGrantedPrivs(granteeID, objRow);
// getGrantedPrivs returns STATUS_GOOD or STATUS_NOTFOUND
// if STATUS_NOTFOUND, bitmaps are empty (as initialized above)
// if STATUS_GOOD, set current bitmaps
if (privStatus == STATUS_GOOD)
{
PrivMgrCoreDesc coreDesc(objRow.privsBitmap_, objRow.grantableBitmap_);
objectUsage.originalPrivs.setTablePrivs(coreDesc);
objectUsage.updatedPrivs.setTablePrivs(coreDesc);
}
// check to see if can revoke if there are referenced items when
// revoke cascade is supported, this returns the list of referenced
// items that need to change.
if ( updateDependentObjects(objectUsage, PrivCommand::REVOKE_COLUMN_RESTRICT) == STATUS_ERROR)
return STATUS_ERROR;
// At this point we have an array of privsToRevoke with column ordinal and
// priv bitmap.
//
// Three revoke column cases:
//
// Spec Spec Priv bitmap compare
// GOF Priv to granted priv bitmap Action
// T 1 NA Removing WGO only. Update operation.
// Reset privType bit in grantable bitmap,
// copy priv bitmap from granted privs.
//
// F 1 Equal Revoking all privs on this column, plus
// WGO. Delete operation.
//
// F 1 Not equal Revoking some privs on this column plus
// WGO for the revoked privs. Reset bits in
// both bitmaps. Update operation.
if (checkColumnRevokeRestrict (granteeID, colPrivsToRevoke, columnRowList_))
return STATUS_ERROR;
bool rowRevoked = false;
PrivColumnBitmap revokedPrivs;
std::string whereBase(" WHERE object_uid = ");
whereBase += UIDToString(objectUID_);
whereBase += " AND grantor_id = ";
whereBase += authIDToString(grantorID_);
whereBase += " AND grantee_id = ";
whereBase += authIDToString(granteeID);
whereBase += " AND column_number = ";
ColumnPrivsMDTable columnPrivsTable(columnTableName_,pDiags_);
for (size_t i = 0; i < colPrivsToRevoke.entries(); i++)
{
PrivMgrCoreDesc &colPrivToRevoke = colPrivsToRevoke[i];
bool updateRow = false;
bool deleteRow = false;
// Look for any existing granted privileges on the column for which
// privileges are to be granted.
PrivMgrCoreDesc *grantedColPriv = findColumnEntry(grantedColPrivs, colPrivToRevoke.getColumnOrdinal());
if (grantedColPriv)
{
// Found row with grant for this column.
// Verify privilege(s) being revoked was/were granted. If not, continue
if (!isWGOSpecified &&
((colPrivToRevoke.getPrivBitmap() & grantedColPriv->getPrivBitmap()) == 0))
continue;
// If all privileges are revoked, delete corresponding row
if (!isWGOSpecified &&
(colPrivToRevoke.getPrivBitmap() == grantedColPriv->getPrivBitmap()))
deleteRow = true;
else
updateRow = true;
// generate the final bitmaps to store in metadata
// removing any privileges that already have been revoked
PrivMgrCoreDesc adjustedPrivs = *grantedColPriv;
adjustedPrivs.AndNot(colPrivToRevoke);
// If only removing WGO, then the privsBitmap does not change
// Not sure if this is needed ??
if (isWGOSpecified)
adjustedPrivs.setPrivBitmap(grantedColPriv->getPrivBitmap());
// set adjusted privileges
colPrivToRevoke.setPrivBitmap(adjustedPrivs.getPrivBitmap());
colPrivToRevoke.setWgoBitmap(adjustedPrivs.getWgoBitmap());
// Using the list of privs to revoke, change so adjustedPrivs contains
// Some privileges may have been requested to revoke that aren't
// currently granted - flip adjusted bits to final list of privs
revokedPrivs |= adjustedPrivs.getPrivBitmap();
}
else
{
// The row should exist in "grantedColPrivs"
PRIVMGR_INTERNAL_ERROR("Column privilege not found to revoke");
return STATUS_ERROR;
}
if (deleteRow)
{
std::string whereClause(whereBase + authIDToString(colPrivToRevoke.getColumnOrdinal()));
privStatus = columnPrivsTable.deleteWhere(whereClause);
if (privStatus == STATUS_ERROR)
return privStatus;
rowRevoked = true;
continue;
}
if (!updateRow)
{
PRIVMGR_INTERNAL_ERROR("Column privilege not found to revoke");
return STATUS_ERROR;
}
ColumnPrivsMDRow row;
row.objectUID_ = objectUID_;
row.objectName_ = objectName_;
row.granteeID_ = granteeID;
row.granteeName_ = granteeName;
row.grantorID_ = grantorID_;
row.grantorName_ = grantorName;
row.privsBitmap_ = colPrivToRevoke.getPrivBitmap();
row.grantableBitmap_ = colPrivToRevoke.getWgoBitmap();
row.columnOrdinal_ = colPrivToRevoke.getColumnOrdinal();
privStatus = columnPrivsTable.updateColumnRow(row,whereBase);
if (privStatus == STATUS_ERROR)
return privStatus;
rowRevoked = true;
}
// if (!rowRevoked)
// Warning
return STATUS_GOOD;
}
//************* End of PrivMgrPrivileges::revokeColumnPriv ***************
// *****************************************************************************
// * Method: revokeObjectPriv
// *
// * Deletes or updates a row in the OBJECT_PRIVILEGES table.
// *
// * Parameters:
// *
// * <objectType> is the type of the subject object.
// * <granteeID> is the unique identifier for the grantee
// * <privsList> is the list of privileges to revoke
// * <isAllSpecified> if true then all privileges valid for the object
// * type will be revoked
// * <isGOFSpecified> if true then remove the ability for the grantee
// * to revoke the set of privileges to other grantees
// *
// * Returns: PrivStatus
// *
// * STATUS_GOOD: Privileges were granted
// * *: Unable to grant privileges, see diags.
// *
// *****************************************************************************
PrivStatus PrivMgrPrivileges::revokeObjectPriv (const ComObjectType objectType,
const int32_t granteeID,
const std::string & granteeName,
const std::string & grantorName,
const std::vector<PrivType> &privsList,
const std::vector<ColPrivSpec> & colPrivsArray,
const bool isAllSpecified,
const bool isGOFSpecified)
{
PrivStatus retcode = STATUS_GOOD;
std::string traceMsg;
log (__FILE__, "****** REVOKE operation begins ******", -1);
PrivMgrDesc privsToRevoke(granteeID);
PrivMgrDesc privsOfTheGrantor(grantorID_);
std::vector<int_32> roleIDs;
retcode = initGrantRevoke(objectType, granteeID, grantorName,
privsList, colPrivsArray,
isAllSpecified, isGOFSpecified, false,
privsToRevoke, privsOfTheGrantor, roleIDs);
if (retcode != STATUS_GOOD)
return retcode;
// Remove any privsToRevoke which are not held grantable by the Grantor.
// If limitToGrantable returns true, some privs are not revokable.
bool warnNotAll = false;
PrivMgrDesc origPrivsToRevoke = privsToRevoke;
if ( privsToRevoke.limitToGrantable( privsOfTheGrantor ) )
{
// This is ok. Can specify ALL without having all privileges set.
if (!isAllSpecified )
warnNotAll = true; // Not all the specified privs can be revoked
}
// If nothing left to revoke, we are done.
if ( privsToRevoke.isNull() )
{
std::string rolesWithPrivs;
if (getRolesToCheck(grantorID_, roleIDs, objectType, rolesWithPrivs)== STATUS_GOOD)
{
if (rolesWithPrivs.size() > 0)
{
*pDiags_ << DgSqlCode (-CAT_PRIVILEGE_NOT_GRANTED)
<< DgString0 (grantorName.c_str())
<< DgString1 (rolesWithPrivs.c_str());
return STATUS_ERROR;
}
}
*pDiags_ << DgSqlCode (-CAT_PRIVILEGE_NOT_GRANTED)
<< DgString0 (grantorName.c_str());
return STATUS_ERROR;
}
// revoke any column level privileges
if ( !privsToRevoke.isColumnLevelNull() )
{
retcode = revokeColumnPriv(objectType,granteeID,granteeName,
grantorName,privsToRevoke,isGOFSpecified);
if (retcode != STATUS_GOOD)
return retcode;
}
// If only column-level privileges were specified, no problem.
if (privsToRevoke.getTablePrivs().isNull())
{
// Send a message to the Trafodion RMS process about the revoke operation.
// RMS will contact all master executors and ask that cached privilege
// information be re-calculated
retcode = sendSecurityKeysToRMS(granteeID, privsToRevoke);
// report any privs not granted
if (warnNotAll)
reportPrivWarnings(origPrivsToRevoke,
privsToRevoke,
CAT_NOT_ALL_PRIVILEGES_REVOKED);
log (__FILE__, "****** REVOKE operation succeeded ******", -1);
return STATUS_GOOD;
}
// See if grantor has previously granted privileges to the grantee
ObjectPrivsMDRow row;
retcode = getGrantedPrivs(granteeID, row);
if (retcode == STATUS_ERROR)
return retcode;
if (retcode == STATUS_NOTFOUND)
{
// Set up parameters for the error message: privileges, grantor, & grantee
// privilege list
std::string privListStr;
for (size_t i = 0; i < privsList.size(); i++)
privListStr += PrivMgrUserPrivs::convertPrivTypeToLiteral(privsList[i]) + ", ";
privListStr.erase(privListStr.length()-2, privListStr.length());
if (isGOFSpecified)
privListStr += " WITH GRANT OPTION";
*pDiags_ << DgSqlCode (CAT_GRANT_NOT_FOUND)
<< DgString0 (privListStr.c_str())
<< DgString1 (grantorName.c_str())
<<DgString2 (granteeName.c_str());
return STATUS_WARNING;
}
// if privileges exist, set currentPrivs to existing list
// save a copy of the original privs
PrivMgrCoreDesc currentPrivs; // creates an empty descriptor
PrivMgrCoreDesc tempPrivs(row.privsBitmap_, row.grantableBitmap_);
currentPrivs = tempPrivs;
PrivMgrCoreDesc savedOriginalPrivs = currentPrivs;
// TDB: if user privs have already been revoked, just return
// save the privsToRevoke for query invalidation(QI) later
PrivMgrDesc listOfRevokedPrivileges = privsToRevoke;
// merge requested changes with existing row
// First flip privsToRevoke to turn off the privilege and then union
// the current privs with the privsToRevoke to generate the final bitmaps
privsToRevoke.complement();
privsToRevoke.intersectionOfPrivs(currentPrivs);
row.privsBitmap_ = privsToRevoke.getTablePrivs().getPrivBitmap();
row.grantableBitmap_ = privsToRevoke.getTablePrivs().getWgoBitmap();
// See if there are any dependencies that need to be removed before
// removing the privilege
ObjectUsage objectUsage;
objectUsage.objectUID = objectUID_;
objectUsage.granteeID = granteeID;
objectUsage.grantorIsSystem = false;
objectUsage.objectName = row.objectName_;
objectUsage.objectType = row.objectType_;
objectUsage.columnReferences = NULL;
PrivMgrDesc originalPrivs (row.granteeID_);
originalPrivs.setTablePrivs(savedOriginalPrivs);
objectUsage.originalPrivs = originalPrivs;
objectUsage.updatedPrivs = privsToRevoke;
if (updateDependentObjects(objectUsage, PrivCommand::REVOKE_OBJECT_RESTRICT) == STATUS_ERROR)
return STATUS_ERROR;
// Go rebuild the privilege tree to see if it is broken
// If it is broken, return an error
if (checkRevokeRestrict (row, objectRowList_))
return STATUS_ERROR;
ObjectPrivsMDTable objectPrivsTable (objectTableName_, pDiags_);
if (privsToRevoke.getTablePrivs().isNull())
{
row.describeRow(traceMsg);
traceMsg.insert(0, "deleting privilege row ");
log (__FILE__, traceMsg, -1);
// delete the row
retcode = objectPrivsTable.deleteRow(row);
}
else
{
row.describeRow(traceMsg);
traceMsg.insert(0, "updating existing privilege row ");
log (__FILE__, traceMsg, -1);
// update the row
retcode = objectPrivsTable.updateRow(row);
}
// Send a message to the Trafodion RMS process about the revoke operation.
// RMS will contact all master executors and ask that cached privilege
// information be re-calculated
retcode = sendSecurityKeysToRMS(granteeID, listOfRevokedPrivileges);
// SQL Ansi states that privileges that can be revoked should be done so
// even if some requested privilege are not revokable.
// TDB: report which privileges were not revoked
if (warnNotAll)
reportPrivWarnings(origPrivsToRevoke,
privsToRevoke,
CAT_NOT_ALL_PRIVILEGES_REVOKED);
log (__FILE__, "****** REVOKE operation succeeded ******", -1);
return retcode;
}
// *****************************************************************************
// * Method: revokeObjectPriv
// *
// * Deletes rows in the OBJECT_PRIVILEGES table associated with the object
// * This code assumes that all dependent and referencing objects such as
// * views have been (or will be) dropped. No extra checks are performed.
// *
// * Returns: PrivStatus
// *
// * STATUS_GOOD: Privileges were revoked
// * *: Unable to revoke privileges, see diags.
// *
// *****************************************************************************
PrivStatus PrivMgrPrivileges::revokeObjectPriv ()
{
PrivStatus retcode = STATUS_GOOD;
if (objectUID_ == 0)
{
PRIVMGR_INTERNAL_ERROR("objectUID is 0 for revoke command");
return STATUS_ERROR;
}
char buf[100];
sprintf(buf, "where object_uid = %ld", objectUID_);
std::string whereClause = buf;
// delete all the rows for this object
ObjectPrivsMDTable objectPrivsTable (objectTableName_, pDiags_);
retcode = objectPrivsTable.deleteWhere(whereClause);
ColumnPrivsMDTable columnPrivsTable (objectTableName_, pDiags_);
retcode = columnPrivsTable.deleteWhere(whereClause);
return retcode;
}
// ----------------------------------------------------------------------------
// method: checkRevokeRestrict
//
// This method starts at the beginning of the privilege tree and rebuilds
// it from top to bottom. If the revoke causes part of the tree to be
// unaccessible (a broken branch), it returns true; otherwise, revoke can
// proceed - returns false.
//
// Params:
// rowIn - the row containing proposed changes from the requested
// revoke statement.
// rowList - a list of all the rows associated with the object
//
// true - unable to perform revoke because of dependencies
// false - able to perform revoke.privileges
//
// The diags area is set up with where the tree was broken
// ----------------------------------------------------------------------------
bool PrivMgrPrivileges::checkRevokeRestrict (
PrivMgrMDRow &rowIn,
std::vector <PrivMgrMDRow *> &rowList )
{
// Search the list of privileges associated with the object and replace
// the bitmaps of the current row with the bitmaps of the row sent in (rowIn).
// At the same time, clear visited_ and set current_ to row values
ObjectPrivsMDRow updatedRow = static_cast<ObjectPrivsMDRow &>(rowIn);
std::string traceMsg;
log (__FILE__, "checking grant tree for broken branches", -1);
for (int32_t i = 0; i < rowList.size(); i++)
{
// if rowIn matches this row, then update the bitmaps to use the
// updated bitmaps
ObjectPrivsMDRow &currentRow = static_cast<ObjectPrivsMDRow &> (*rowList[i]);
if (updatedRow.granteeID_ == currentRow.granteeID_ &&
updatedRow.grantorID_ == currentRow.grantorID_ )
{
currentRow.privsBitmap_ = updatedRow.privsBitmap_;
currentRow.grantableBitmap_ = updatedRow.grantableBitmap_;
}
// reset visited_ and current_ PrivMgrCoreDesc
currentRow.clearVisited();
currentRow.setToOriginal();
}
// Reconstruct the privilege tree
// Each privilege tree starts with the root - system grantor (-2)
for ( size_t i = 0; i < NBR_OF_PRIVS; i++ )
{
PrivType pType = PrivType(i);
int32_t systemGrantor = SYSTEM_USER;
scanObjectBranch (pType, systemGrantor, rowList);
// TDB - add a scan for column privileges
}
// If a branch of the tree was not visited, then we have a broken
// tree. Therefore, revoke restrict will leave abandoned privileges
// in the case, return true.
bool notVisited = false;
for (size_t i = 0; i < rowList.size(); i++)
{
ObjectPrivsMDRow &currentRow = static_cast<ObjectPrivsMDRow &> (*rowList[i]);
currentRow.describeRow(traceMsg);
log (__FILE__, traceMsg, i);
if (currentRow.anyNotVisited())
{
*pDiags_ << DgSqlCode(-CAT_DEPENDENT_PRIV_EXISTS)
<< DgString0(currentRow.grantorName_.c_str())
<< DgString1(currentRow.granteeName_.c_str());
log (__FILE__, "found a branch that is not accessible", -1);
notVisited = true;
break;
}
}
return notVisited;
}
// ----------------------------------------------------------------------------
// method: scanObjectBranch
//
// scans the privsList entries for match on Grantor,
// keeping track of which priv/wgo entries have been encountered
// by setting "visited" flag in the entry.
//
// For each entry discovered, set visited flag to indicate that
// priv and wgo were seen. For wgo, if the wgo visited flag has not
// already been set, call scanObjectBranch recursively with this grantee
// as grantor. (By observing the state of the wgo visited flag
// we avoid redundantly exploring the sub-tree rooted in a grantor
// which has already been discovered as having wgo from some other
// ancestor grantor.)
//
// This algorithm produces a depth-first scan of all nodes of the
// directed graph of privilege settings which can currently be reached
// by an uninterrupted chain of wgo values.
//
// The implementation is dependent on the fact that PrivsList
// entries are ordered by Grantor, Grantee, and within each of these
// by Primary uid value, type. Entries for system grantor (_SYSTEM) are the
// first entries in the list.
//
// -----------------------------------------------------------------------------
void PrivMgrPrivileges::scanObjectBranch( const PrivType pType, // in
const int32_t& grantor, // in
const std::vector<PrivMgrMDRow *> & privsList ) // in
{
// The PrivMgrMDRow <list> is maintained in order by
// Grantee within Grantor value - through an order by clause.
// Skip over Grantors lower than the specified one.
size_t i = 0;
while ( i < privsList.size() )
{
ObjectPrivsMDRow &currentRow = static_cast<ObjectPrivsMDRow &> (*privsList[i]);
if (currentRow.grantorID_ < grantor)
i++;
else
break;
}
// For matching Grantor, process each Grantee.
while ( i < privsList.size() )
{
ObjectPrivsMDRow &privEntry = static_cast<ObjectPrivsMDRow &> (*privsList[i]);
if (privEntry.grantorID_ == grantor)
{
PrivMgrCoreDesc& current = privEntry.accessCurrent();
if ( current.getPriv(pType) )
{
// This grantee has priv. Set corresponding visited flag.
PrivMgrCoreDesc& visited = privEntry.accessVisited();
visited.setPriv(pType, true);
if ( current.getWgo(pType))
{
// This grantee has wgo.
if ( visited.getWgo(pType) )
{ // Already processed this subtree.
}
else
{
visited.setWgo(pType, true);
int32_t thisGrantee( privEntry.granteeID_ );
if ( ComUser::isPublicUserID(thisGrantee) )
scanPublic( pType, // Deal with PUBLIC grantee wgo.
privsList );
else
{
int32_t granteeAsGrantor;
if (isRoleID(thisGrantee))
{
std::vector<int32_t> roleIDs;
std::vector<int32_t> userIDs;
roleIDs.push_back(thisGrantee);
if (getUserIDsForRoleIDs(roleIDs,userIDs) == STATUS_ERROR)
return;
for (size_t j = 0; j < userIDs.size(); j++)
{
granteeAsGrantor = userIDs[j];
scanObjectBranch( pType, // Scan for this grantee as grantor.
granteeAsGrantor,
privsList );
}
}
granteeAsGrantor = thisGrantee;
scanObjectBranch( pType, // Scan for this grantee as grantor.
granteeAsGrantor,
privsList );
}
}
} // end this grantee has wgo
} // end this grantee has this priv
i++; // on to next privsList entry
}
else
break;
} // end scan privsList over Grantees for this Grantor
} // end scanCurrent
/* *******************************************************************
scanPublic -- a grant wgo to PUBLIC has been encountered for the
current privilege type, so *all* users are able to grant this privilege.
Scan the privsList for all grantees who have this priv from any grantor,
marking each such entry as visited.
****************************************************************** */
void PrivMgrPrivileges::scanPublic( const PrivType pType, // in
const std::vector<PrivMgrMDRow *>& privsList ) // in
{
// PUBLIC has a priv wgo. So *every* grant of this priv
// is allowed, by any Grantor.
for ( size_t i = 0; i < privsList.size(); i++ )
{
ObjectPrivsMDRow &privEntry = static_cast<ObjectPrivsMDRow &> (*privsList[i]);
const PrivMgrCoreDesc& current = privEntry.accessCurrent();
if ( current.getPriv(pType) )
{
// This grantee has priv. Set corresponding visited flag.
PrivMgrCoreDesc& visited = privEntry.accessVisited();
visited.setPriv(pType, true);
if ( current.getWgo(pType) )
visited.setWgo(pType, true);
}
} // end scan privsList over all Grantees/Grantors
} // end scanPublic
// ----------------------------------------------------------------------------
// method: checkColumnRevokeRestrict
//
// This method starts at the beginning of the privilege tree and rebuilds
// it from top to bottom. If the revoke causes part of the tree to be
// unaccessible (a broken branch), it returns true; otherwise, revoke can
// proceed - returns false.
//
// Params:
// granteeID - the target AuthID
// colPrivsToRevoke - the list of column entries containing proposed
// changes from the requested revoke statement.
// rowList - a list of all the rows associated with the object
//
// true - unable to perform revoke because of dependencies
// false - able to perform revoke.privileges
//
// The diags area is set up with where the tree was broken
// ----------------------------------------------------------------------------
bool PrivMgrPrivileges::checkColumnRevokeRestrict (
int32_t granteeID,
const NAList<PrivMgrCoreDesc> &colPrivsToRevoke,
std::vector <PrivMgrMDRow *> &rowList )
{
std::string traceMsg;
log (__FILE__, "checking column grant tree for broken branches", -1);
// Clear visited_ bitmaps and set current_ bitmaps to current priv values
// Search the list of privileges associated with the object and turn off
// the bitmaps in current_ that are no longer available when the revoke
// completes - based on colPrivsToRevoke.
for (int32_t i = 0; i < rowList.size(); i++)
{
ColumnPrivsMDRow &currentRow = static_cast<ColumnPrivsMDRow &> (*rowList[i]);
currentRow.setCurrentToOriginal();
currentRow.clearVisited();
// only look at rows for the current grantor and grantee
if (currentRow.grantorID_ == grantorID_ &&
currentRow.granteeID_ == granteeID)
{
// Adjust rows that have had their privileges updated
for (int32_t j = 0; j < colPrivsToRevoke.entries(); j++)
{
PrivMgrCoreDesc updatedEntry = (PrivMgrCoreDesc)colPrivsToRevoke[j];
if (updatedEntry.getColumnOrdinal() == currentRow.columnOrdinal_)
{
PrivColumnBitmap newPrivBitmap = updatedEntry.getPrivBitmap() ^= currentRow.privsBitmap_;
PrivColumnBitmap temp = updatedEntry.getWgoBitmap().flip();
PrivColumnBitmap newGrantableBitmap = temp &= currentRow.grantableBitmap_;
currentRow.current_.setPrivBitmap(newPrivBitmap);
currentRow.current_.setWgoBitmap(newGrantableBitmap);
traceMsg = "Adjusted current_ to reflect revoked privileges";
traceMsg += ", grantor is ";
traceMsg += to_string((long long int)currentRow.grantorID_);
traceMsg += ", grantee is ";
traceMsg += to_string((long long int) currentRow.granteeID_);
log (__FILE__, traceMsg, -1);
}
}
}
}
// Reconstruct the privilege tree based on the adjusted privileges
// starting with the object owner - get the object owner.
PrivMgrObjects objects(trafMetadataLocation_,pDiags_);
int32_t objectOwner = 0;
PrivStatus privStatus = objects.fetchObjectOwner(objectUID_,objectOwner);
if (privStatus == STATUS_ERROR)
{
PRIVMGR_INTERNAL_ERROR("Could not fetch object owner");
return true;
}
// Create the list of columns that have been changed, during
// reconstruction, only look at rows that have changes.
// std::set does not add entries if they already exist.
std::set<int32_t> listOfColumnOrdinals;
for ( size_t i = 0; i < colPrivsToRevoke.entries(); i++)
{
PrivMgrCoreDesc colPrivToRevoke = colPrivsToRevoke[i];
listOfColumnOrdinals.insert(colPrivToRevoke.getColumnOrdinal());
}
// Reconstruct tree
for ( size_t i = 0; i < NBR_DML_COL_PRIVS; i++ )
{
scanColumnBranch (PrivType(i), objectOwner, listOfColumnOrdinals, rowList);
}
// If a branch of the tree was not visited, then we have a broken
// tree. Therefore, revoke restrict will leave abandoned privileges
// in the case, return true.
bool notVisited = false;
for (size_t i = 0; i < rowList.size(); i++)
{
ColumnPrivsMDRow &currentRow = static_cast<ColumnPrivsMDRow &> (*rowList[i]);
// Only look at rows that have been changed
for (std::set<int32_t>::iterator it = listOfColumnOrdinals.begin();
it!= listOfColumnOrdinals.end(); ++it)
{
if (*it == currentRow.columnOrdinal_)
{
currentRow.describeRow(traceMsg);
log (__FILE__, traceMsg, i);
if (currentRow.anyNotVisited())
{
*pDiags_ << DgSqlCode(-CAT_DEPENDENT_PRIV_EXISTS)
<< DgString0(currentRow.grantorName_.c_str())
<< DgString1(currentRow.granteeName_.c_str());
log (__FILE__, "found a branch that is not accessible", -1);
notVisited = true;
break;
}
}
}
}
return notVisited;
}
// ----------------------------------------------------------------------------
// method: scanColumnBranch
//
// scans the privsList entries for match on Grantor,
// keeping track of which priv/wgo entries have been encountered
// by setting "visited" flag in the entry.
//
// For each entry discovered, set visited flag to indicate that
// priv and wgo were seen. For wgo, if the wgo visited flag has not
// already been set, call scanObjectBranch recursively with this grantee
// as grantor. (By observing the state of the wgo visited flag
// we avoid redundantly exploring the sub-tree rooted in a grantor
// which has already been discovered as having wgo from some other
// ancestor grantor.)
//
// This algorithm produces a depth-first scan of all nodes of the
// directed graph of privilege settings which can currently be reached
// by an uninterrupted chain of wgo values.
//
// The implementation is dependent on the fact that rowList
// entries are ordered by Grantor, Grantee, columnOrdinal
// -----------------------------------------------------------------------------
void PrivMgrPrivileges::scanColumnBranch( const PrivType pType,
const int32_t& grantor,
const std::set<int32_t> &listOfColumnOrdinals,
const std::vector<PrivMgrMDRow *> & rowList )
{
// The PrivMgrMDRow <list> is maintained in order by
// columnOrdinal within Grantee within Grantor - through an order by clause.
// Skip over Grantors lower than the specified one.
size_t i = 0;
while ( i < rowList.size() )
{
ColumnPrivsMDRow &currentRow = static_cast<ColumnPrivsMDRow &> (*rowList[i]);
if (currentRow.grantorID_ < grantor)
i++;
else
break;
}
// For matching Grantor, process each Grantee.
while ( i < rowList.size() )
{
ColumnPrivsMDRow &currentRow = static_cast<ColumnPrivsMDRow &> (*rowList[i]);
if (currentRow.grantorID_ == grantor)
{
// Just look at rows that have had privileges changed
// The listOfColumnOrdinals has this list
PrivMgrCoreDesc current = currentRow.current_;
std::set<int32_t>::iterator it;
it = std::find(listOfColumnOrdinals.begin(), listOfColumnOrdinals.end(), current.getColumnOrdinal());
if (it != listOfColumnOrdinals.end())
{
if ( current.getPrivBitmap().test(pType) )
{
// This grantee has priv. Set corresponding visited flag.
currentRow.visited_.setPriv(pType, true);
if ( current.getWgoBitmap().test(pType))
{
// This grantee has wgo.
if ( currentRow.visited_.getWgoBitmap().test(pType) )
{ // Already processed this subtree.
}
else
{
currentRow.visited_.setWgo(pType, true);
// To check: since column level privileges do not have
// an anchor, we choose the object owner as the root.
int32_t thisGrantee( currentRow.granteeID_ );
if ( ComUser::isPublicUserID(thisGrantee) )
scanPublic( pType, // Deal with PUBLIC grantee wgo.
rowList );
else
{
int32_t granteeAsGrantor;
if (isRoleID(thisGrantee))
{
std::vector<int32_t> roleIDs;
std::vector<int32_t> userIDs;
roleIDs.push_back(thisGrantee);
if (getUserIDsForRoleIDs(roleIDs,userIDs) == STATUS_ERROR)
return;
for (size_t j = 0; j < userIDs.size(); j++)
{
granteeAsGrantor = userIDs[j];
scanColumnBranch( pType, // Scan for this grantee as grantor.
granteeAsGrantor,
listOfColumnOrdinals,
rowList );
}
}
granteeAsGrantor = thisGrantee;
scanColumnBranch( pType, // Scan for this grantee as grantor.
granteeAsGrantor,
listOfColumnOrdinals,
rowList );
} // end process non public auth ID
} // end visit row
} // end this grantee has wgo
} // end this grantee has this priv
} // correct column ordinal
i++; // on to next rowList entry
}
else
break; // done with the grantor
} // end scan rowList over Grantees for this Grantor
}
/* *******************************************************************
scanColumnPublic -- a grant wgo to PUBLIC has been encountered for the
current privilege type, so *all* users are able to grant this privilege.
Scan the privsList for all grantees who have this priv from any grantor,
marking each such entry as visited.
****************************************************************** */
void PrivMgrPrivileges::scanColumnPublic(
const PrivType pType, // in
const std::set<int32_t> &listOfColumnOrdinals,
const std::vector<PrivMgrMDRow *>& rowList ) // in
{
// PUBLIC has a priv wgo. So *every* grant of this priv
// is allowed, by any Grantor.
for ( size_t i = 0; i < rowList.size(); i++ )
{
ColumnPrivsMDRow &currentRow = static_cast<ColumnPrivsMDRow &> (*rowList[i]);
// Just look at rows that have had privileges changed
// The listOfColumnOrdinals has this list
PrivMgrCoreDesc current = currentRow.current_;
std::set<int32_t>::iterator it;
it = std::find(listOfColumnOrdinals.begin(), listOfColumnOrdinals.end(), current.getColumnOrdinal());
if (it != listOfColumnOrdinals.end())
{
if ( current.getPrivBitmap().test(pType) )
{
// This grantee has priv. Set corresponding visited flag.
currentRow.visited_.setPriv(pType, true);
// This grantee has wgo.
if ( currentRow.visited_.getWgoBitmap().test(pType) )
currentRow.visited_.setWgo(pType, true);
}
}
} // end scan privsList over all Grantees/Grantors
} // end scanPublic
// ****************************************************************************
// method: sendSecurityKeysToRMS
//
// This method generates a security key for each privilege revoked for the
// grantee. It then makes a cli call sending the keys.
// SQL_EXEC_SetSecInvalidKeys will send the security keys to RMS and RMS
// sends then to all the master executors. The master executors check this
// list and recompile any queries to recheck privileges.
//
// input:
// granteeID - the UID of the user losing privileges
// the granteeID is stored in the PrivMgrDesc class - extra?
// revokedPrivs - the list of privileges that were revoked
//
// Returns: PrivStatus
//
// STATUS_GOOD: Privileges were granted
// *: Unable to send keys, see diags.
// ****************************************************************************
PrivStatus PrivMgrPrivileges::sendSecurityKeysToRMS(
const int32_t granteeID,
const PrivMgrDesc &revokedPrivs)
{
// Go through the list of table privileges and generate SQL_QIKEYs
std::vector<ComSecurityKey *> keyList;
const PrivMgrCoreDesc &privs = revokedPrivs.getTablePrivs();
PrivStatus privStatus = buildSecurityKeys(granteeID,
revokedPrivs.getTablePrivs(),
keyList);
if (privStatus != STATUS_GOOD)
{
for(size_t k = 0; k < keyList.size(); k++)
delete keyList[k];
keyList.clear();
return privStatus;
}
for (int i = 0; i < revokedPrivs.getColumnPrivs().entries(); i++)
{
const NAList<PrivMgrCoreDesc> &columnPrivs = revokedPrivs.getColumnPrivs();
privStatus = buildSecurityKeys(granteeID,
columnPrivs[i],
keyList);
if (privStatus != STATUS_GOOD)
{
for(size_t k = 0; k < keyList.size(); k++)
delete keyList[k];
keyList.clear();
return privStatus;
}
}
// Create an array of SQL_QIKEYs
int32_t numKeys = keyList.size();
SQL_QIKEY siKeyList[numKeys];
for (size_t j = 0; j < keyList.size(); j++)
{
ComSecurityKey *pKey = keyList[j];
siKeyList[j].revokeKey.subject = pKey->getSubjectHashValue();
siKeyList[j].revokeKey.object = pKey->getObjectHashValue();
std::string actionString;
pKey->getSecurityKeyTypeAsLit(actionString);
strncpy(siKeyList[j].operation, actionString.c_str(), 2);
}
// delete the security list
for(size_t k = 0; k < keyList.size(); k++)
delete keyList[k];
keyList.clear();
// Call the CLI to send details to RMS
SQL_EXEC_SetSecInvalidKeys(numKeys, siKeyList);
return STATUS_GOOD;
}
// *****************************************************************************
// * Method: populateObjectPriv
// *
// * Inserts rows into the OBJECT_PRIVILEGES table during initialization to
// * reflect object owner privileges
// *
// * Parameters:
// *
// * <objectLocation> the location of the Trafodion OBJECTS table which is
// * used to extract all the objects
// * <authsLocation> the location of the Trafodion AUTHS table which is used
// * to map owner IDs to grantees
// *
// * Returns: PrivStatus
// *
// * STATUS_GOOD: Privileges were inserted
// * *: Unable to insert privileges, see diags.
// *
// *****************************************************************************
PrivStatus PrivMgrPrivileges::populateObjectPriv(
const std::string &objectsLocation,
const std::string &authsLocation)
{
// bug - sometimes, if don't wait, the insert command
// does not find rows to insert
//sleep(60);
ObjectPrivsMDTable objectPrivsTable(objectTableName_, pDiags_);
return objectPrivsTable.insertSelect(objectsLocation, authsLocation);
}
// *****************************************************************************
// * Method: getPrivBitmaps
// *
// * Reads the OBJECT_PRIVILEGES table to get the privilege bitmaps for
// * rows matching a where clause.
// *
// * Parameters:
// *
// * <whereClause> specifies the rows to be returned
// * <orderByClause> specifies the order of the rows to be returned
// * <privBitmaps> passes back a vector of bitmaps.
// *
// * Returns: PrivStatus
// *
// * STATUS_GOOD: Privileges were returned
// * *: Unable to read privileges, see diags.
// *
// *****************************************************************************
PrivStatus PrivMgrPrivileges::getPrivBitmaps(
const std::string & whereClause,
const std::string & orderByClause,
std::vector<PrivObjectBitmap> & privBitmaps)
{
std::vector<PrivMgrMDRow *> rowList;
ObjectPrivsMDTable objectPrivsTable(objectTableName_,pDiags_);
PrivStatus privStatus = objectPrivsTable.selectWhere(whereClause, orderByClause,rowList);
if (privStatus != STATUS_GOOD)
{
deleteRowList(rowList);
return privStatus;
}
for (size_t r = 0; r < rowList.size(); r++)
{
ObjectPrivsMDRow &row = static_cast<ObjectPrivsMDRow &>(*rowList[r]);
privBitmaps.push_back(row.privsBitmap_);
}
deleteRowList(rowList);
return STATUS_GOOD;
}
// *****************************************************************************
// * Method: getPrivTextForObject
// *
// * returns GRANT statements describing all the privileges that have been
// * granted on the object
// *
// * Parameters:
// *
// * <objectInfo> Metadata details for object.
// * <privilegeText> The resultant GRANT statement(s)
// *
// * Returns: PrivStatus
// *
// * STATUS_GOOD : Grants were found
// * STATUS_NOTFOUND: No grants were found
// * *: Unable to insert privileges, see diags.
// *
// *****************************************************************************
PrivStatus PrivMgrPrivileges::getPrivTextForObject(
const PrivMgrObjectInfo & objectInfo,
std::string & privilegeText)
{
PrivStatus retcode = STATUS_GOOD;
if (objectUID_ == 0)
{
PRIVMGR_INTERNAL_ERROR("objectUID is 0 for describe privileges command");
return STATUS_ERROR;
}
// generate the list of privileges granted to the object and store in class
if (generateObjectRowList() == STATUS_ERROR)
return STATUS_ERROR;
if (generateColumnRowList() == STATUS_ERROR)
return STATUS_ERROR;
// No failures possible for objects, all information in rowList.
buildPrivText(objectRowList_,objectInfo,PrivLevel::OBJECT,pDiags_,privilegeText);
// build text for columns
retcode = buildPrivText(columnRowList_,objectInfo,PrivLevel::COLUMN,
pDiags_,privilegeText);
return retcode;
}
// *****************************************************************************
// * Method: getPrivsOnObjectForUser
// *
// * returns privileges granted to the requested user for the requested
// * object
// *
// * Parameters:
// *
// * <objectUID> identifies the object
// * <userID> identifies the user
// * <privsOfTheUser> the list of privileges is returned
// *
// * Returns: PrivStatus
// *
// * STATUS_GOOD: Privileges were gathered
// * *: Unable to gather privileges, see diags.
// *
// *****************************************************************************
PrivStatus PrivMgrPrivileges::getPrivsOnObjectForUser(
const int64_t objectUID,
ComObjectType objectType,
const int32_t userID,
PrivMgrDesc &privsOfTheUser,
std::vector <ComSecurityKey *>* secKeySet)
{
PrivStatus retcode = STATUS_GOOD;
objectUID_ = objectUID;
if (objectUID == 0)
{
PRIVMGR_INTERNAL_ERROR("objectUID is 0 for get privileges command");
return STATUS_ERROR;
}
// generate the list of privileges granted to the object and store in class
if (generateObjectRowList() == STATUS_ERROR)
return STATUS_ERROR;
// generate the list of column-level privileges granted to the object and store in class
if (generateColumnRowList() == STATUS_ERROR)
return STATUS_ERROR;
// generate the list of roles for the user
std::vector<int32_t> roleIDs;
if (getRoleIDsForUserID(userID,roleIDs) == STATUS_ERROR)
return STATUS_ERROR;
// generate the list of privileges for the user
privsOfTheUser.setGrantee(userID);
bool hasManagePrivileges = false;
retcode = getUserPrivs(objectType, userID, roleIDs, privsOfTheUser,
hasManagePrivileges, secKeySet);
return retcode;
}
// *****************************************************************************
// * Method: getRoleIDsForUserID
// *
// * Returns the roleIDs for the roles granted to the user.
// *
// * Parameters:
// *
// * <userID> is the unique identifier for the user
// * <roleIDs> passes back the list (potentially empty) of roles granted to the user
// *
// * Returns: PrivStatus
// *
// * STATUS_GOOD: Role list returned
// * *: Unable to fetch granted roles, see diags.
// *
// *****************************************************************************
PrivStatus PrivMgrPrivileges::getRoleIDsForUserID(
int32_t userID,
std::vector<int32_t> & roleIDs)
{
PrivStatus retcode = STATUS_GOOD;
PrivMgrRoles roles(" ",metadataLocation_,pDiags_);
std::vector<std::string> roleNames;
std::vector<int32_t> roleDepths;
retcode = roles.fetchRolesForUser(userID,roleNames,roleIDs,roleDepths);
return retcode;
}
//*************** End of PrivMgrPrivileges::getRoleIDsForUserID ****************
// *****************************************************************************
// * Method: getUserIDsForRoleIDs
// *
// * Returns the userIDs granted to the role passed in role list
// *
// * Parameters:
// *
// * <roleIDs> list of roles to check
// * <userIDs> passed back the list (potentially empty) of users granted to
// * the roleIDs
// *
// * Returns: PrivStatus
// *
// * STATUS_GOOD: Role list returned
// * *: Unable to fetch granted roles, see diags.
// *
// *****************************************************************************
PrivStatus PrivMgrPrivileges::getUserIDsForRoleIDs(
const std::vector<int32_t> & roleIDs,
std::vector<int32_t> & userIDs)
{
std::vector<int32_t> userIDsForRoleIDs;
PrivMgrRoles roles(" ",metadataLocation_,pDiags_);
if (roles.fetchUsersForRoles(roleIDs, userIDsForRoleIDs) == STATUS_ERROR)
return STATUS_ERROR;
for (size_t i = 0; i < userIDsForRoleIDs.size(); i++)
{
int32_t authID = userIDsForRoleIDs[i];
if (std::find(userIDs.begin(), userIDs.end(), authID) == userIDs.end())
userIDs.insert( std::upper_bound( userIDs.begin(), userIDs.end(), authID ), authID);
}
return STATUS_GOOD;
}
// *****************************************************************************
// * Method: getUserPrivs
// *
// * Accumulates privileges for a user summarized over all grantors
// * including PUBLIC
// *
// * Parameters:
// *
// * <objectType> is the type of the subject object.
// * <granteeID> specifies the userID to accumulate
// * <roleIDs> specifies a list of roles granted to the grantee
// * <summarizedPrivs> contains the summarized privileges
// * <hasManagePrivileges> returns whether the grantee has MANAGE_PRIVILEGES authority
// * <secKeySet> if not NULL, returns a set of keys for user
// *
// * Returns: PrivStatus
// *
// * STATUS_GOOD: Privileges were gathered
// * *: Unable to gather privileges, see diags.
// *
// *****************************************************************************
PrivStatus PrivMgrPrivileges::getUserPrivs(
ComObjectType objectType,
const int32_t granteeID,
const std::vector<int32_t> & roleIDs,
PrivMgrDesc &summarizedPrivs,
bool & hasManagePrivileges,
std::vector<ComSecurityKey *>* secKeySet
)
{
PrivStatus retcode = STATUS_GOOD;
PrivMgrDesc temp(granteeID);
retcode = getPrivsFromAllGrantors( objectUID_,
objectType,
granteeID,
roleIDs,
temp,
hasManagePrivileges,
secKeySet
);
if (retcode != STATUS_GOOD)
return retcode;
summarizedPrivs = temp;
return retcode;
}
// *****************************************************************************
// * Method: getPrivsFromAllGrantors
// *
// * Accumulates privileges for a specified userID
// * Does the actual accumulation orchestrated by getUserPrivs
// *
// * Parameters:
// *
// * <objectUID> object to gather privileges for
// * <objectType> is the type of the subject object.
// * <granteeID> specifies the userID to accumulate
// * <roleIDs> is vector of roleIDs granted to the grantee
// * <hasManagePrivileges> returns whether the grantee has MANAGE_PRIVILEGES authority
// * <summarizedPrivs> contains the summarized privileges
// *
// * Returns: PrivStatus
// *
// * STATUS_GOOD: Privileges were accumulated
// * *: Unable to accumulate privileges, see diags.
// *
// *****************************************************************************
PrivStatus PrivMgrPrivileges::getPrivsFromAllGrantors(
const int64_t objectUID,
ComObjectType objectType,
const int32_t granteeID,
const std::vector<int32_t> & roleIDs,
PrivMgrDesc &summarizedPrivs,
bool & hasManagePrivileges,
std::vector <ComSecurityKey *>* secKeySet
)
{
PrivStatus retcode = STATUS_GOOD;
hasManagePrivileges = false;
bool hasPublicGrantee = false;
// Check to see if the granteeID is the system user
// if so, the system user has all privileges. Set up appropriately
if (ComUser::isSystemUserID(granteeID))
{
PrivObjectBitmap bitmap;
bitmap.set();
PrivMgrCoreDesc coreTablePrivs(bitmap, bitmap);
summarizedPrivs.setTablePrivs(coreTablePrivs);
hasManagePrivileges = true;
return STATUS_GOOD;
}
std::vector<PrivMgrMDRow *> rowList;
PrivObjectBitmap systemPrivs;
PrivMgrComponentPrivileges componentPrivileges(metadataLocation_,pDiags_);
componentPrivileges.getSQLDMLPrivileges(granteeID,roleIDs,systemPrivs,
hasManagePrivileges);
if (hasManagePrivileges && hasAllDMLPrivs(objectType,systemPrivs))
{
PrivMgrCoreDesc coreTablePrivs(systemPrivs,systemPrivs);
summarizedPrivs.setTablePrivs(coreTablePrivs);
}
// Accumulate object level privileges
else
{
retcode = getRowsForGrantee(objectUID, granteeID, true, roleIDs, rowList, secKeySet);
if (retcode == STATUS_ERROR)
return retcode;
// Get the privileges for the object granted to the grantee
PrivMgrCoreDesc coreTablePrivs;
for (int32_t i = 0; i < rowList.size();++i)
{
ObjectPrivsMDRow &row = static_cast<ObjectPrivsMDRow &> (*rowList[i]);
if (ComUser::isPublicUserID(row.granteeID_))
hasPublicGrantee = true;
PrivMgrCoreDesc temp (row.privsBitmap_, row.grantableBitmap_);
if (secKeySet)
{
retcode = buildSecurityKeys(granteeID,
temp,
*secKeySet);
if (retcode == STATUS_ERROR)
return retcode;
}
coreTablePrivs.unionOfPrivs(temp);
}
PrivObjectBitmap grantableBitmap;
if (hasManagePrivileges)
grantableBitmap = systemPrivs;
PrivMgrCoreDesc temp2(systemPrivs,grantableBitmap);
coreTablePrivs.unionOfPrivs(temp2);
summarizedPrivs.setTablePrivs(coreTablePrivs);
}
// Add accumulated column level privileges
rowList.clear();
retcode = getRowsForGrantee(objectUID, granteeID, false, roleIDs, rowList, secKeySet);
if (retcode == STATUS_ERROR)
return retcode;
NAList<PrivMgrCoreDesc> coreColumnPrivs(STMTHEAP);
for (int32_t i = 0; i < rowList.size();++i)
{
ColumnPrivsMDRow &row = static_cast<ColumnPrivsMDRow &> (*rowList[i]);
if (ComUser::isPublicUserID(row.granteeID_))
hasPublicGrantee = true;
// See if the ordinal has already been specified
PrivMgrCoreDesc temp (row.privsBitmap_, row.grantableBitmap_, row.columnOrdinal_);
if (secKeySet)
{
retcode = buildSecurityKeys(granteeID,
temp,
*secKeySet);
if (retcode == STATUS_ERROR)
return retcode;
}
PrivMgrCoreDesc *coreColumnPriv = findColumnEntry(coreColumnPrivs, row.columnOrdinal_);
if (coreColumnPriv)
coreColumnPriv->unionOfPrivs(temp);
else
coreColumnPrivs.insert(temp);
}
summarizedPrivs.setColumnPrivs(coreColumnPrivs);
summarizedPrivs.setHasPublicPriv(hasPublicGrantee);
return STATUS_GOOD;
}
// ----------------------------------------------------------------------------
// method: getRolesToCheck
//
// This method checks all the roles granted to the user and returns a comma
// separated list of those roles that have privileges on the target object.
// ----------------------------------------------------------------------------
PrivStatus PrivMgrPrivileges::getRolesToCheck(
const int32_t grantorID,
const std::vector<int32_t> & roleIDs,
const ComObjectType objectType,
std::string &rolesWithPrivs)
{
int32_t length;
char roleName[MAX_DBUSERNAME_LEN + 1];
std::vector<int_32> emptyRoleIDs;
bool hasManagePrivPriv = false;
for (size_t r = 0; r < roleIDs.size(); r++)
{
PrivMgrDesc privsOfTheRole(roleIDs[r],true);
if (getUserPrivs(objectType, roleIDs[r], emptyRoleIDs, privsOfTheRole,
hasManagePrivPriv) != STATUS_GOOD)
return STATUS_ERROR;
if (!privsOfTheRole.isNull())
{
// just return what getAuthNameFromAuthID returns
ComUser::getAuthNameFromAuthID(roleIDs[r],roleName, sizeof(roleName),length);
if (rolesWithPrivs.size() > 0)
rolesWithPrivs += ", ";
rolesWithPrivs += roleName;
}
}
if (rolesWithPrivs.size() > 0)
{
rolesWithPrivs.insert (0,"Please retry using the BY clause for one of the following roles (");
rolesWithPrivs += ").";
}
return STATUS_GOOD;
}
// *****************************************************************************
// * Method: getRowsForGrantee
// *
// * Reads OBJECT_PRIVILEGES table to obtain all privileges granted to the
// * specified granteeID for the object (objectUID)
// *
// * Parameters:
// *
// * <objectUID> object to gather privileges for
// * <granteeID> specifies the userID to gather privileges
// * <roleIDs> the list of roles granted to the userID
// * <isObjectTable> true if OBJECT_PRIVILEGES table
// * <rowList> returns the list of granted privileges as a vector list
// * consisiting of the grantor, grantee, and privileges for the object
// *
// * Returns: PrivStatus
// *
// * STATUS_GOOD: Privileges were retrieved
// * *: Unable to retrieve privileges, see diags.
// *
// *****************************************************************************
PrivStatus PrivMgrPrivileges::getRowsForGrantee(
const int64_t objectUID,
const int32_t granteeID,
const bool isObjectTable,
const std::vector<int_32> &roleIDs,
std::vector<PrivMgrMDRow *> &rowList,
std::vector <ComSecurityKey *>* secKeySet)
{
PrivStatus retcode = STATUS_GOOD;
// create the list of row pointers
std::vector<int32_t> authIDs = roleIDs;
authIDs.push_back(granteeID);
authIDs.push_back(PUBLIC_USER);
std::vector<int32_t>::iterator it;
std::vector<PrivMgrMDRow *> privRowList;
if (isObjectTable)
{
if (objectUID == objectUID_)
privRowList = objectRowList_;
else
{
retcode = getObjectRowList(objectUID, privRowList);
if (retcode == STATUS_ERROR)
return retcode;
}
}
else
privRowList = columnRowList_;
for (size_t i = 0; i < privRowList.size(); i++)
{
if (isObjectTable)
{
ObjectPrivsMDRow &row = static_cast<ObjectPrivsMDRow &> (*privRowList[i]);
it = std::find(authIDs.begin(), authIDs.end(), row.granteeID_);
}
else
{
ColumnPrivsMDRow &row = static_cast<ColumnPrivsMDRow &> (*privRowList[i]);
it = std::find(authIDs.begin(), authIDs.end(), row.granteeID_);
}
if (it != authIDs.end())
rowList.push_back(privRowList[i]);
}
return STATUS_GOOD;
}
// ****************************************************************************
// method: summarizeColPrivs
//
// This method summarizes column privileges across all grantors.
//
// Params:
// objectReference - the affected object
// roleIDs - list of roles for the current object owner
// listOfAffectedObjects - list of affected objects
// summarizedColRefs - a list of ColumnReference pointers that contain the
// summarized privileges (the caller is responsible
// for deleting memory for this parameter
// ****************************************************************************
void PrivMgrPrivileges::summarizeColPrivs(
const ObjectReference &objReference,
const int32_t granteeID,
const int32_t grantorID,
const std::vector<int32_t> &roleIDs,
const std::vector<ObjectUsage *> &listOfAffectedObjects,
std::vector<ColumnReference *> &summarizedColRefs)
{
std::string traceMsg;
objReference.describe(traceMsg);
traceMsg.insert (0, "summarizing column privileges ");
log (__FILE__, traceMsg, -1);
// objReference.columnReferences is the list of columns
// referencing the referenced table
std::vector<ColumnReference *> *colRefs = objReference.columnReferences;
for (size_t i = 0; i < colRefs->size(); i++)
{
ColumnReference *colRef = (*colRefs)[i];
colRef->describe(traceMsg);
log (__FILE__, traceMsg, i);
// get COLUMN_PRIVILEGES rows where the grantee for the column has received
// privileges - the row list is in memory so this does not require I/O
std::vector<PrivMgrMDRow *> rowList;
getColRowsForGranteeOrdinal(granteeID,
colRef->columnOrdinal,
columnRowList_,
roleIDs,
rowList);
// go through the rowList to summarize the original and current privileges
// We do a union operation to capture privileges from all grantors
ColumnReference *summarized = new ColumnReference;
summarized->columnOrdinal = colRef->columnOrdinal;
if (rowList.size() > 0)
{
for (int32_t j = 0; j < rowList.size();++j)
{
ColumnPrivsMDRow &row = static_cast<ColumnPrivsMDRow &> (*rowList[j]);
PrivMgrCoreDesc originalPrivs(row.privsBitmap_, row.grantableBitmap_);
PrivMgrCoreDesc updated = originalPrivs;
// Update if privileges have been changed by request
for (size_t k = 0; k < listOfAffectedObjects.size(); k++)
{
ObjectUsage *currentObj = listOfAffectedObjects[k];
if (currentObj->objectUID == row.objectUID_ &&
grantorID == row.grantorID_ &&
currentObj->granteeID == row.granteeID_ )
{
ColumnReference *changedRef = currentObj->findColumn(row.columnOrdinal_);
if (changedRef)
updated = changedRef->updatedPrivs;
}
}
summarized->originalPrivs.unionOfPrivs(originalPrivs);
summarized->updatedPrivs.unionOfPrivs(updated);
}
}
else
{
// For grants, this may be the first column privs added, adjust to
// include new privs
PrivMgrCoreDesc updated;
for (size_t k = 0; k < listOfAffectedObjects.size(); k++)
{
ObjectUsage *currentObj = listOfAffectedObjects[k];
ColumnReference *changedRef = currentObj->findColumn(colRef->columnOrdinal);
if (changedRef)
updated = changedRef->updatedPrivs;
}
// There are no originalPrivs
summarized->updatedPrivs.unionOfPrivs(updated);
}
// Add column ref to the list
summarizedColRefs.push_back(summarized);
}
}
// *****************************************************************************
// * Method: summarizeCurrentAndOriginalPrivs
// *
// * Accumulates privileges for a specified object and grantee
// *
// * Parameters:
// *
// * <objectUID> object to summarize privileges for
// * <granteeID> specifies the userID to accumulate
// * <roleIDs> the list of roles granted to the userID
// * <summarizedOriginalPrivs> contains the original summarized privileges
// * <summarizedCurrentPrivs> contains the current summarized privileges
// *
// * Returns: PrivStatus
// *
// * STATUS_GOOD: Privileges were summarized
// * *: Unable to summarize privileges, see diags.
// *
// *****************************************************************************
PrivStatus PrivMgrPrivileges::summarizeCurrentAndOriginalPrivs(
const int64_t objectUID,
const int32_t granteeID,
const int32_t grantorID,
const std::vector<int32_t> & roleIDs,
const std::vector<ObjectUsage *> listOfChangedPrivs,
PrivMgrDesc &summarizedOriginalPrivs,
PrivMgrDesc &summarizedCurrentPrivs)
{
PrivStatus retcode = STATUS_GOOD;
// get OBJECT_PRIVILEGES rows where the grantee has received privileges
std::vector<PrivMgrMDRow *> rowList;
retcode = getRowsForGrantee(objectUID, granteeID, true, roleIDs, rowList, NULL);
// rowList contains the original privileges,
// listOfChangedPrivs contains any updates to privileges
// go through the list and summarize the original and current privileges
// We do a union operation to capture privileges from all grantors
for (int32_t i = 0; i < rowList.size();++i)
{
ObjectPrivsMDRow &row = static_cast<ObjectPrivsMDRow &> (*rowList[i]);
PrivMgrCoreDesc original(row.privsBitmap_, row.grantableBitmap_);
PrivMgrCoreDesc updated = original;
for (size_t j = 0; j < listOfChangedPrivs.size(); j++)
{
ObjectUsage *pObjectUsage = listOfChangedPrivs[j];
if (pObjectUsage->objectUID == row.objectUID_ &&
grantorID == row.grantorID_ &&
pObjectUsage->granteeID == row.granteeID_ )
{
updated = pObjectUsage->updatedPrivs.getTablePrivs();
}
}
summarizedOriginalPrivs.unionOfPrivs(original);
summarizedCurrentPrivs.unionOfPrivs(updated);
}
return STATUS_GOOD;
}
// *****************************************************************************
// * Method: updateDependentObjects
// *
// * This code gets the list of dependent objects that have had their privileges
// * changed because of the ongoing grant/revoke request. It then updates
// * the object privileges table to change any dependencies.
// *
// * SQL ANSI general rules state
// *
// * - When granting INSERT, UPDATE, or DELETE object or column privilege to
// * a table that is referenced by one or more views, then the privilege
// * should be propagated to any updatable views that reference the table.
// * The grant request to the these views should be executed as though the
// * current user is _SYSTEM.
// *
// * - If the table already has SELECT privilege and a new grant is
// * performed that adds the WITH GRANT OPTION, then the WITH GRANT OPTION
// * is to be propagated to referencing views. The grant request should
// * be executed as though the current user is _SYSTEM.
// *
// * - When revoking INSERT, UPDATE, or DELETE object or column privilege from
// * a table that is referenced by one or more views, then the privilege
// * should be revoked on any updatable views that reference the table.
// * The revoke request to the these views should be executed as though the
// * current user is _SYSTEM.
// *
// * - If the revoke is performed that removes the WITH GRANT OPTION, then
// * the WITH GRANT OPTION is to be removed frome referencing views. The
// * revoke request should be executed as though the current user is _SYSTEM.
// *
// *****************************************************************************
PrivStatus PrivMgrPrivileges::updateDependentObjects(
const ObjectUsage &objectUsage,
const PrivCommand command)
{
std::string traceMsg;
// get list of any objects that need to change because of the grant/revoke
std::vector<ObjectUsage *> listOfObjects;
PrivStatus privStatus = getAffectedObjects(objectUsage, command, listOfObjects);
if (privStatus == STATUS_ERROR)
{
deleteListOfAffectedObjects(listOfObjects);
return privStatus;
}
traceMsg = "list of dependent objects, number of objects is ";
traceMsg += to_string((long long int)listOfObjects.size());
log (__FILE__, traceMsg, -1);
char buf [1000];
ObjectPrivsMDTable objectPrivsTable (objectTableName_, pDiags_);
// update the OBJECT_PRIVILEGES row for each effected object
// Starting index is 1 - the first entry is the original row that is
// updated as part of the grant/revoke request
size_t i = 1;
for (i; i < listOfObjects.size(); i++)
{
ObjectUsage *pObjectUsage = listOfObjects[i];
pObjectUsage->describe(traceMsg);
log (__FILE__, traceMsg, i);
// Determine row contents
int32_t theGrantor = (pObjectUsage->grantorIsSystem) ? SYSTEM_USER : grantorID_;
int32_t theGrantee = pObjectUsage->granteeID;
int64_t theUID = pObjectUsage->objectUID;
PrivMgrCoreDesc thePrivs = pObjectUsage->updatedPrivs.getTablePrivs();
sprintf(buf, "where grantee_id = %d and grantor_id = %d and object_uid = %ld",
theGrantee, theGrantor, theUID);
std::string whereClause (buf);
if (thePrivs.isNull())
{
pObjectUsage->describe(traceMsg);
traceMsg.insert (0, "deleted object usage ");
// delete the row
privStatus = objectPrivsTable.deleteWhere(whereClause);
if (privStatus == STATUS_ERROR)
{
deleteListOfAffectedObjects(listOfObjects);
return privStatus;
}
}
else
{
sprintf(buf, "set privileges_bitmap = %ld, grantable_bitmap = %ld",
thePrivs.getPrivBitmap().to_ulong(),
thePrivs.getWgoBitmap().to_ulong());
std::string setClause (buf);
privStatus = objectPrivsTable.updateWhere(setClause, whereClause);
if (privStatus == STATUS_ERROR)
{
deleteListOfAffectedObjects(listOfObjects);
return privStatus;
}
}
}
deleteListOfAffectedObjects(listOfObjects);
return STATUS_GOOD;
}
// *****************************************************************************
// * Method: isAuthIDGrantedPrivs
// *
// * Determines if the specified authorization ID has been granted one or
// * more object privileges.
// *
// * Parameters:
// *
// * <authID> identifies the user or role.
// *
// * Returns: bool
// *
// * true: Authorization ID has been granted one or more object privileges.
// * false: Authorization ID has not been granted any object privileges.
// *
// *****************************************************************************
bool PrivMgrPrivileges::isAuthIDGrantedPrivs(
const int32_t authID,
std::vector<int64_t> &objectUIDs)
{
std::string whereClause(" WHERE GRANTEE_ID = ");
std::string orderByClause (" ORDER BY object_name ");
char authIDString[20];
sprintf(authIDString,"%d",authID);
whereClause += authIDString;
// set pointer in diags area
int32_t diagsMark = pDiags_->mark();
std::vector<PrivMgrMDRow *> rowList;
ObjectPrivsMDTable myTable(objectTableName_,pDiags_);
PrivStatus privStatus = myTable.selectWhere(whereClause, orderByClause ,rowList);
if (privStatus != STATUS_GOOD)
{
deleteRowList(rowList);
return privStatus;
}
int32_t rowCount = rowList.size();
for (size_t i = 0; i < rowCount; i++)
{
ObjectPrivsMDRow &row = static_cast<ObjectPrivsMDRow &> (*rowList[i]);
objectUIDs.push_back(row.objectUID_);
}
deleteRowList(rowList);
if ((privStatus == STATUS_GOOD || privStatus == STATUS_WARNING) &&
rowCount > 0)
return true;
// TBD - check for granted column level privs
pDiags_->rewind(diagsMark);
return false;
}
// *****************************************************************************
// * Method: convertPrivsToDesc
// *
// * Converts the list of requested privileges into a PrivMgrDesc
// * This code also checks for duplicate entries in the privilege list
// * and that the list of privileges is compatible with the object type.
// *
// * Parameters:
// *
// * <objectType> type of object
// * <isAllSpecified> if true then all privileges valid for the object
// * type will be revoked
// * <isWGOSpecified> for grants, include the with grant option
// * for revokes (always true), if revoke the priv, also
// * revoke the with grant option
// * <isGofSpecified> for grants - alway false (not applicable)
// * for revokes - only revoke the with grant option
// * <privsList> is the list of privileges to check
// * <PrivMgrCoreDesc> the core descriptor containing privileges
// *
// * Returns: PrivStatus
// *
// * STATUS_GOOD: Privileges were inserted
// * *: Unable to insert privileges, see diags.
// *
// *****************************************************************************
PrivStatus PrivMgrPrivileges::convertPrivsToDesc(
const ComObjectType objectType,
const bool isAllSpecified,
const bool isWgoSpecified,
const bool isGofSpecified,
const std::vector<PrivType> privsList,
const std::vector<ColPrivSpec> & colPrivsList,
PrivMgrDesc &privsToProcess)
{
// Categorize the objectType
bool isLibrary = false;
bool isUdr = false;
bool isObject = false;
bool isSequence = false;
switch (objectType)
{
case COM_BASE_TABLE_OBJECT:
case COM_VIEW_OBJECT:
isObject = true;
break;
case COM_LIBRARY_OBJECT:
isLibrary = true;
break;
case COM_USER_DEFINED_ROUTINE_OBJECT:
isUdr = true;
break;
case COM_SEQUENCE_GENERATOR_OBJECT:
isSequence = true;
break;
default:
{
char objectTypeLit[3] = {0};
strncpy(objectTypeLit,ObjectEnumToLit(objectType),2);
*pDiags_ << DgSqlCode(-4219)
<< DgString1(objectTypeLit);
return STATUS_ERROR;
}
}
// If all is specified, set bits appropriate for the object type and return
if (isAllSpecified)
{
if (isLibrary)
privsToProcess.setAllLibraryGrantPrivileges(isWgoSpecified);
else if (isUdr)
privsToProcess.setAllUdrGrantPrivileges(isWgoSpecified);
else if (isSequence)
privsToProcess.setAllSequenceGrantPrivileges(isWgoSpecified);
else
privsToProcess.setAllTableGrantPrivileges(isWgoSpecified);
return STATUS_GOOD;
}
PrivMgrCoreDesc tableCorePrivs;
// For each privilege specified in the privsList:
// make sure it is not a duplicate
// make sure it is appropriate for the objectType
bool isIncompatible = false;
for (int32_t i = 0; i < privsList.size();++i)
{
switch (privsList[i])
{
case EXECUTE_PRIV:
if (!isUdr)
isIncompatible = true;
else
tableCorePrivs.testAndSetBit(privsList[i],isWgoSpecified,isGofSpecified);
break;
case DELETE_PRIV:
case INSERT_PRIV:
case REFERENCES_PRIV:
case SELECT_PRIV:
if (!isObject)
isIncompatible = true;
else
tableCorePrivs.testAndSetBit(privsList[i],isWgoSpecified,isGofSpecified);
break;
case UPDATE_PRIV:
if (!isObject && !isLibrary)
isIncompatible = true;
else
tableCorePrivs.testAndSetBit(privsList[i],isWgoSpecified,isGofSpecified);
break;
case USAGE_PRIV:
if (!isLibrary && !isSequence)
isIncompatible = true;
else
tableCorePrivs.testAndSetBit(privsList[i],isWgoSpecified,isGofSpecified);
break;
case ALL_DML:
if (!isObject)
isIncompatible = true;
if (isGofSpecified)
tableCorePrivs.setWgo(ALL_DML,true);
else
{
tableCorePrivs.setPriv(ALL_DML,true);
tableCorePrivs.setWgo(ALL_DML,isWgoSpecified);
}
break;
default:
{
*pDiags_ << DgSqlCode(-CAT_INVALID_PRIVILEGE_FOR_GRANT_OR_REVOKE)
<< DgString0(PrivMgrUserPrivs::convertPrivTypeToLiteral(privsList[i]).c_str());
return STATUS_ERROR;
}
}
// Report error if privilege is incompatible with objectType
if (isIncompatible)
{
*pDiags_ << DgSqlCode(-CAT_PRIVILEGE_NOT_ALLOWED_FOR_THIS_OBJECT_TYPE)
<< DgString0(PrivMgrUserPrivs::convertPrivTypeToLiteral(privsList[i]).c_str());
return STATUS_ERROR;
}
} // end for
privsToProcess.setTablePrivs(tableCorePrivs);
// Merge the column-privilege-to-grant entries (colPrivArray) into one entry
// per column ordinal.
//
// Example: Given a commands such as
//
// GRANT SELECT(COL4),INSERT(COL2,COL4) ON TAB TO USER;
//
// three entries are generated by the parser, but only two rows are written;
// one for column 2 (insert) and one for column 4 (insert and select).
//
// Input may have same column ordinal in multiple entries, but the input is
// guaranteed not to contain same ordinal and privType more than once.
NAList<PrivMgrCoreDesc> columnCorePrivs(STMTHEAP);
for (size_t i = 0; i < colPrivsList.size(); i++)
{
const ColPrivSpec &colPrivSpec = colPrivsList[i];
PrivMgrCoreDesc *existingEntry = findColumnEntry(columnCorePrivs,
colPrivSpec.columnOrdinal);
if (existingEntry != NULL)
existingEntry->testAndSetBit(colPrivSpec.privType,isWgoSpecified,isGofSpecified);
else
{
PrivMgrCoreDesc colPrivToGrant;
colPrivToGrant.setColumnOrdinal(colPrivSpec.columnOrdinal);
colPrivToGrant.testAndSetBit(colPrivSpec.privType,isWgoSpecified,isGofSpecified);
columnCorePrivs.insert(colPrivToGrant);
}
}
privsToProcess.setColumnPrivs(columnCorePrivs);
return STATUS_GOOD;
}
// *****************************************************************************
// PrivMgrPrivileges.cpp static functions *
// *****************************************************************************
// *****************************************************************************
// * Function: buildPrivText *
// * *
// * Builds priv portion of SHOWDDL output. *
// * *
// *****************************************************************************
// * *
// * Parameters: *
// * *
// * <rowList> const std::vector<PrivMgrMDRow *> In *
// * is a list of rows describing the privileges granted. *
// * *
// * <objectInfo> const PrivMgrObjectInf & In *
// * object details needed to create appropriate text *
// * *
// * <privLevel> PrivLevel In *
// * is the privilege level, either OBJECT or COLUMN. *
// * *
// * <pDiags_> ComDiagsArea * In *
// * is where to report an internal error. *
// * *
// * <privilegeText> std::string & Out *
// * passes back the set of grant commands that describe the privileges on *
// * the object. *
// * *
// *****************************************************************************
static PrivStatus buildPrivText(
const std::vector<PrivMgrMDRow *> rowList,
const PrivMgrObjectInfo & objectInfoIn,
PrivLevel privLevel,
ComDiagsArea * pDiags_,
std::string & privilegeText)
{
PrivMgrObjectInfo objectInfo = (PrivMgrObjectInfo) objectInfoIn;
// Build a grant statement for each grantor/grantee row returned.
// TDB: If we support multiple grantees per grant statement,
// this code can be improved
std::string grantStmt;
std::string grantWGOStmt;
std::string objectText("ON ");
// Append object type if not base table or view
if (objectInfo.getObjectType() != COM_BASE_TABLE_OBJECT &&
objectInfo.getObjectType() != COM_VIEW_OBJECT)
objectText += comObjectTypeName(objectInfo.getObjectType());
objectText += objectInfo.getObjectName() + " TO ";
std::string lastGranteeName;
int32_t lastGranteeID = 0;
std::vector<std::string> privString;
std::vector<std::string> WGOString;
std::vector<bool> hasWGO;
std::vector<bool> hasPriv;
std::vector<std::string> columnNames;
bool mergeStrings = false;
// Note, this creates entries for DELETE and USAGE that are unused.
if (privLevel == PrivLevel::COLUMN)
for (size_t p = FIRST_DML_COL_PRIV; p <= LAST_DML_COL_PRIV; p++ )
{
privString.push_back(PrivMgrUserPrivs::convertPrivTypeToLiteral((PrivType)p) + "(");
WGOString.push_back(privString[p]);
hasPriv.push_back(false);
hasWGO.push_back(false);
}
for (int32_t i = 0; i < rowList.size();++i)
{
std::string objectGranteeText(objectText);
std::string withoutWGO;
std::string withWGO;
int32_t grantorID = 0;
std::string grantorName;
if (privLevel == PrivLevel::OBJECT)
{
ObjectPrivsMDRow &row = static_cast<ObjectPrivsMDRow &> (*rowList[i]);
grantorID = row.grantorID_;
grantorName = row.grantorName_;
PrivObjectBitmap privsBitmap = row.privsBitmap_;
PrivObjectBitmap wgoBitmap = row.grantableBitmap_;
bool delimited = isDelimited(row.granteeName_);
if (delimited)
objectGranteeText += "\"";
objectGranteeText += row.granteeName_;
if (delimited)
objectGranteeText += "\"";
for (size_t p = FIRST_DML_PRIV; p <= LAST_DML_PRIV; p++ )
if (privsBitmap.test(p))
{
std::string privTypeString =
PrivMgrUserPrivs::convertPrivTypeToLiteral((PrivType)p);
if (wgoBitmap.test(p))
withWGO += privTypeString + ", ";
else
withoutWGO += privTypeString + ", ";
}
}
else
{
ColumnPrivsMDRow &row = static_cast<ColumnPrivsMDRow &> (*rowList[i]);
// For column-level privileges we are building a piece of the
// output for each privilege on every loop. Privileges are stored
// per column, but GRANT syntax accepts via a privilege and a
// list of columns. For each privilege granted to a grantee, need
// to list all the columns. Substrings are merged when the end of the
// list of grants is reached or there is a new grantor or grantee.
if (i + 1 == rowList.size())
mergeStrings = true;
else
{
ColumnPrivsMDRow &nextRow = static_cast<ColumnPrivsMDRow &> (*rowList[i + 1]);
if (nextRow.grantorID_ != row.grantorID_ ||
nextRow.granteeID_ != row.granteeID_)
mergeStrings = true;
}
grantorID = row.grantorID_;
grantorName = row.grantorName_;
PrivColumnBitmap privsBitmap = row.privsBitmap_;
PrivColumnBitmap wgoBitmap = row.grantableBitmap_;
// Get name of the grantee. If we have changed grantees, fetch the
// name of the grantee.
if (row.granteeID_ != lastGranteeID)
{
lastGranteeID = row.granteeID_;
lastGranteeName = row.granteeName_;
}
bool delimited = isDelimited(lastGranteeName);
if (delimited)
objectGranteeText += "\"";
objectGranteeText += lastGranteeName;
if (delimited)
objectGranteeText += "\"";
// Get the column name for the row
const std::vector<std::string> &columnList = objectInfo.getColumnList();
if (columnList.size() < row.columnOrdinal_)
{
std::string errorText("Unable to look up column name for column number ");
errorText += PrivMgr::authIDToString(row.columnOrdinal_);
PRIVMGR_INTERNAL_ERROR(errorText.c_str());
return STATUS_ERROR;
}
std::string columnName(columnList.at(row.columnOrdinal_));
// Build the list of columns granted for each privilege. WGOString
// and privString have been pre-populated with PRIVNAME(.
for (size_t p = FIRST_DML_COL_PRIV; p <= LAST_DML_COL_PRIV; p++ )
if (privsBitmap.test(p))
{
if (wgoBitmap.test(p))
{
WGOString[p] += columnName + ", ";
hasWGO[p] = true;
}
else
{
privString[p] += columnName + ", ";
hasPriv[p] = true;
}
}
// Check if there are column priv substrings that need to be merged.
if (mergeStrings)
{
for (size_t p = FIRST_DML_COL_PRIV; p <= LAST_DML_COL_PRIV; p++ )
{
if (!isDMLPrivType(static_cast<PrivType>(p)))
continue;
// See if any WGO statement exist
if (hasWGO[p])
{
closeColumnList(WGOString[p]);
withWGO += WGOString[p];
// Reset to original value
WGOString[p].assign(PrivMgrUserPrivs::convertPrivTypeToLiteral((PrivType)p) + "(");
hasWGO[p] = false;
}
// See if any WGO statement exist
if (hasPriv[p])
{
closeColumnList(privString[p]);
withoutWGO += privString[p];
// Reset to original value
privString[p].assign(PrivMgrUserPrivs::convertPrivTypeToLiteral((PrivType)p) + "(");
hasPriv[p] = false;
}
}
mergeStrings = false;
}
}//End of PrivLevel::COLUMN
if (!withoutWGO.empty())
buildGrantText(withoutWGO,objectGranteeText,
grantorID,grantorName,false,
objectInfo.getObjectOwner(),grantStmt);
if (!withWGO.empty())
buildGrantText(withWGO,objectGranteeText,
grantorID,grantorName,true,
objectInfo.getObjectOwner(),grantWGOStmt);
privilegeText += grantStmt + grantWGOStmt;
grantStmt.clear();
grantWGOStmt.clear();
}
return STATUS_GOOD;
}
//*************************** End of buildPrivText *****************************
// *****************************************************************************
// * Function: buildGrantText *
// * *
// * Builds GRANT statement. *
// * *
// *****************************************************************************
// * *
// * Parameters: *
// * *
// * <privText> const std::string & In *
// * is the privileges granted. *
// * *
// * <objectGranteeText> const std::string & In *
// * is the object the privileges are granted on and to whom. *
// * *
// * <grantorID> const int32_t In *
// * is the ID of the authID who granted the privilege(s). If the system *
// * (_SYSTEM) granted the privilege, the command is prefixed with "--" to *
// * prevent execution in a playback script. *
// * *
// * <isWGO> bool In *
// * if true, add the clause WITH GRANT OPTION to the command. *
// * *
// * <grantText> std::string & Out *
// * passes back the grant command. *
// * *
// *****************************************************************************
void static buildGrantText(
const std::string & privText,
const std::string & objectGranteeText,
const int32_t grantorID,
const std::string grantorName,
bool isWGO,
const int32_t objectOwner,
std::string & grantText)
{
if (grantorID == SYSTEM_USER)
grantText += "-- ";
grantText += "GRANT ";
grantText += privText;
// remove last ','
size_t commaPos = grantText.find_last_of(",");
if (commaPos != std::string::npos)
grantText.replace(commaPos, 1, "");
grantText += objectGranteeText;
if (isWGO)
grantText += " WITH GRANT OPTION";
else
if (grantorID != objectOwner &&
grantorID != SYSTEM_USER)
{
grantText += " GRANTED BY ";
bool delimited = isDelimited(grantorName);
if (delimited)
grantText += "\"";
grantText += grantorName;
if (delimited)
grantText += "\"";
}
grantText += ";\n";
}
//*************************** End of buildGrantText ****************************
// *****************************************************************************
// * Function: closeColumnList *
// * *
// * This function closes a list of the form "(column, column, column, ...".*
// * The last comma is removed and a closing parenthesis is added. *
// * *
// * *
// *****************************************************************************
// * *
// * Parameters: *
// * *
// * <columnList> const std::string & In/Out *
// * is the list of columns in string. *
// * *
// *****************************************************************************
void static closeColumnList(std::string & columnList)
{
size_t commaPos = columnList.find_last_of(",");
// If there is no comma in the string, input not recognized, return unchanged.
if (commaPos == std::string::npos)
return;
// Replace the trailing comma and space with a parenthesis and trailing comma.
// Add an additional trailing space for readability.
columnList.replace(commaPos,2,"),");
columnList += " ";
}
//************************** End of closeColumnList ****************************
// *****************************************************************************
// * *
// * Function: deleteRowList *
// * *
// * Deletes elements from a vector of PrivMgrMDRows. *
// * *
// *****************************************************************************
// * *
// * Parameters: *
// * *
// * <rowList> std::vector<PrivMgrMDRow *> & In/Out *
// * is the list of rows to delete. *
// * *
// * *
// *****************************************************************************
static void deleteRowList(std::vector<PrivMgrMDRow *> & rowList)
{
while(!rowList.empty())
delete rowList.back(), rowList.pop_back();
}
//************************** End of deleteRowList *****************************
// *****************************************************************************
// * Function: findColumnEntry *
// * *
// * This function searches a vector of PrivMgrCoreDesc for a matching *
// * column ordinal. *
// * *
// *****************************************************************************
// * *
// * Parameters: *
// * *
// * *
// * <colPrivEntries> NAList<PrivMgrCoreDesc> & In *
// * is a reference to a vector of ColPrivEntry. *
// * *
// * <columnOrdinal> const int32_t In *
// * is the column ordinal to search for. *
// * *
// *****************************************************************************
// * *
// * Returns: PrivMgrCoreDesc *
// * *
// * NULL: No entry found with that column ordinal *
// * *: Entry found with matching column ordinal *
// * *
// *****************************************************************************
static PrivMgrCoreDesc * findColumnEntry(
NAList<PrivMgrCoreDesc> & colPrivEntries,
const int32_t columnOrdinal)
{
for (size_t i = 0; i < colPrivEntries.entries(); i++)
if (colPrivEntries[i].getColumnOrdinal() == columnOrdinal)
return & colPrivEntries[i];
return NULL;
}
//************************** End of findColumnEntry ****************************
// *****************************************************************************
// * Function: getColRowsForGranteeGrantor *
// * *
// * Returns the list of column privileges granted for the object that have *
// * been granted by the grantorID to the granteeID. *
// * *
// *****************************************************************************
// * *
// * Parameters: *
// * *
// * <columnRowList> std::vector <PrivMgrMDRow *> & In *
// * is the list of column privileges granted to the object. *
// * *
// * <granteeID> const int32_t In *
// * is the authID granted the privileges. *
// * *
// * <grantorID> const int32_t In *
// * is the authID who granted the privileges. *
// * *
// * <grantedColPrivs> NAList<PrivMgrCoreDesc> & Out *
// * passes back a privileges granted to <granteeID> by <grantorID>. *
// * *
// *****************************************************************************
static void getColRowsForGranteeGrantor(
const std::vector <PrivMgrMDRow *> &columnRowList,
const int32_t granteeID,
const int32_t grantorID,
NAList<PrivMgrCoreDesc> & grantedColPrivs)
{
for (size_t i = 0; i < columnRowList.size(); ++i)
{
ColumnPrivsMDRow &row = static_cast<ColumnPrivsMDRow &> (*columnRowList[i]);
PrivMgrCoreDesc colPrivGrant;
if (row.grantorID_ == grantorID && row.granteeID_ == granteeID)
{
colPrivGrant.setColumnOrdinal(row.columnOrdinal_);
colPrivGrant.setPrivBitmap(row.privsBitmap_.to_ulong());
colPrivGrant.setWgoBitmap(row.grantableBitmap_.to_ulong());
grantedColPrivs.insert(colPrivGrant);
}
}
}
//******************* End of getColRowsForGranteeGrantor ***********************
// *****************************************************************************
// * Function: hasAllDMLPrivs *
// * *
// * This function determines if a privilege bitmap has all the DML *
// * privileges for a specified object type. *
// * *
// *****************************************************************************
// * *
// * Parameters: *
// * *
// * <objectType> ComObjectType In *
// * is the type of the object. *
// * *
// * <privBitmap> PrivObjectBitmap In *
// * is the bitmap representing the privileges. *
// * *
// *****************************************************************************
static bool hasAllDMLPrivs(
ComObjectType objectType,
PrivObjectBitmap privBitmap)
{
switch (objectType)
{
case COM_BASE_TABLE_OBJECT:
case COM_VIEW_OBJECT:
if (privBitmap.test(DELETE_PRIV) && privBitmap.test(INSERT_PRIV) &&
privBitmap.test(REFERENCES_PRIV) && privBitmap.test(SELECT_PRIV) &&
privBitmap.test(UPDATE_PRIV))
return true;
break;
case COM_LIBRARY_OBJECT:
if (privBitmap.test(UPDATE_PRIV) && privBitmap.test(USAGE_PRIV))
return true;
break;
case COM_STORED_PROCEDURE_OBJECT:
case COM_USER_DEFINED_ROUTINE_OBJECT:
if (privBitmap.test(EXECUTE_PRIV))
return true;
break;
case COM_SEQUENCE_GENERATOR_OBJECT:
if (privBitmap.test(USAGE_PRIV))
return true;
break;
default:
return false;
}
return false;
}
//************************** End of hasAllDMLPrivs *****************************
// *****************************************************************************
// * *
// * Function: isDelimited *
// * *
// * This function checks the passed in string for characters other than *
// * alphanumeric and underscore characters. If so, the name is delimited *
// * *
// *****************************************************************************
// * *
// * Parameters: *
// * *
// * <strToScan> const std::string & In *
// * is the string to search for delimited characters *
// *****************************************************************************
// * *
// * Returns: bool *
// * *
// * true: the passed in string contains delimited characters *
// * false: the passed in string contains no delimited characters *
// * *
// *****************************************************************************
static bool isDelimited( const std::string &strToScan)
{
char firstChar = strToScan[0];
if (isdigit(firstChar) || strToScan[0] == '_' )
return true;
string validChars = "ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789_";
size_t found = strToScan.find_first_not_of(validChars);
if (found == string::npos)
return false;
return true;
}
//*********************** End of isDelimited ***********************************
// *****************************************************************************
// method: reportPrivWarnings
//
// Ansi states that when a grant statement is executed, a set of privilege
// descriptors (CPD) is created based on existing privileges for the object and
// object’s columns. Each CPD contains the grantee, action (privileges), object,
// column and grantor. A similar list of privilege descriptors is created based
// on the grant/revoke statement (GPD).
//
// If there is an element in the GPD (what the user requested) that is not in
// the CPD (what was actually granted/revoked), then a warning – privilege not
// granted/revoked is displayed.
//
// This method compares the list of actual privileges granted/revoked
// (actualPrivs)to the list privileges requested (origPrivs). If a privilege
// was requested but not granted/revoked report a warning.
// *****************************************************************************
void PrivMgrPrivileges::reportPrivWarnings(
const PrivMgrDesc &origPrivs,
const PrivMgrDesc &actualPrivs,
const CatErrorCode warningCode)
{
PrivMgrCoreDesc objPrivsNotApplied = origPrivs.getTablePrivs();
objPrivsNotApplied.suppressDuplicatedPrivs(actualPrivs.getTablePrivs());
if (!objPrivsNotApplied.isNull())
{
for ( size_t i = FIRST_DML_PRIV; i <= LAST_DML_PRIV; i++ )
{
PrivType privType = PrivType(i);
if (objPrivsNotApplied.getPriv(privType))
{
*pDiags_ << DgSqlCode(warningCode)
<< DgString0(PrivMgrUserPrivs::convertPrivTypeToLiteral(privType).c_str());
}
}
}
NAList<PrivMgrCoreDesc> colPrivs = origPrivs.getColumnPrivs();
for (int i = 0; i < colPrivs.entries(); i++)
{
PrivMgrCoreDesc colPrivsNotApplied = colPrivs[i];
int index = actualPrivs.getColumnPriv(i);
if (index >= 0)
{
PrivMgrCoreDesc colPrivsActual = actualPrivs.getColumnPrivs()[index];
colPrivsNotApplied.suppressDuplicatedPrivs(colPrivsActual);
}
if (!colPrivsNotApplied.isNull())
{
for ( size_t j = FIRST_DML_PRIV; j <= LAST_DML_PRIV; j++ )
{
PrivType privType = PrivType(j);
if (colPrivsNotApplied.getPriv(privType))
{
// would be better to add column name instead of number
// would require an I/O to read COLUMNS to get the name
// associated with the number
char privStr[100];
snprintf(privStr, sizeof(privStr), "%s (column number %d) ",
PrivMgrUserPrivs::convertPrivTypeToLiteral(privType).c_str(),
colPrivsNotApplied.getColumnOrdinal());
*pDiags_ << DgSqlCode(warningCode)
<< DgString0(privStr);
}
}
}
}
}
// *****************************************************************************
// ObjectPrivsMDRow methods
// *****************************************************************************
void ObjectPrivsMDRow::describeRow (std::string &rowDetails)
{
rowDetails = "OBJECT_PRIVILEGES row: type is ";
char objectTypeLit[3] = {0};
strncpy(objectTypeLit,PrivMgr::ObjectEnumToLit(objectType_),2);
rowDetails += objectTypeLit;
rowDetails += ", UID is ";
rowDetails += to_string((long long int) objectUID_);
rowDetails += ", grantor is ";
rowDetails += to_string((long long int)grantorID_);
rowDetails += ", grantee is ";
rowDetails += to_string((long long int) granteeID_);
}
// *****************************************************************************
// ObjectPrivsMDTable methods
// *****************************************************************************
// *****************************************************************************
// * method: ObjectPrivsMDTable::selectWhereUnique
// *
// * Select the row from the OBJECT_PRIVILEGES table based on the specified
// * WHERE clause - where clause should only return a single row
// *
// * Parameters:
// *
// * <whereClause> is the WHERE clause specifying a unique row.
// * <rowOut> passes back a set of OBJECT_PRIVILEGES rows
// *
// * Returns: PrivStatus
// *
// * STATUS_GOOD: Row returned.
// * *: Select failed. A CLI error is put into the diags area.
// *****************************************************************************
PrivStatus ObjectPrivsMDTable::selectWhereUnique(
const std::string & whereClause,
PrivMgrMDRow & rowOut)
{
ObjectPrivsMDRow & row = static_cast<ObjectPrivsMDRow &>(rowOut);
PrivStatus retcode = STATUS_GOOD;
// Should space be allocated and deleted from the heap for the rowList?
// -- how many rows will be returned?
std::vector<PrivMgrMDRow* > rowList;
std::string orderByClause;
retcode = selectWhere(whereClause, orderByClause, rowList);
if (retcode == STATUS_GOOD)
{
// The I/O should be performed on a primary key so only one row returned
// If not, return an internal error
if (rowList.size() != 1)
{
while(!rowList.empty())
delete rowList.back(), rowList.pop_back();
PRIVMGR_INTERNAL_ERROR("Select unique for object_privileges table returned more than 1 row");
return STATUS_ERROR;
}
row = static_cast<ObjectPrivsMDRow &>(*rowList[0]);
}
while(!rowList.empty())
delete rowList.back(), rowList.pop_back();
return retcode;
}
// *****************************************************************************
// * method: ObjectPrivsMDTable::selectWhere
// *
// * Selects rows from the OBJECT_PRIVILEGES table based on the specified
// * WHERE clause.
// *
// * Parameters:
// *
// * <whereClause> is the WHERE clause
// * <orderByClause> is the ORDER BY clause defining returned row order.
// * <rowOut> passes back a set of OBJECT_PRIVILEGES rows
// *
// * Returns: PrivStatus
// *
// * STATUS_GOOD: Row returned.
// * *: Select failed. A CLI error is put into the diags area.
// *****************************************************************************
PrivStatus ObjectPrivsMDTable::selectWhere(
const std::string & whereClause,
const std::string & orderByClause,
std::vector<PrivMgrMDRow *> &rowList)
{
std::string selectStmt ("SELECT OBJECT_UID, OBJECT_NAME, OBJECT_TYPE, ");
selectStmt += ("GRANTEE_ID, GRANTEE_NAME, GRANTEE_TYPE, ");
selectStmt += ("GRANTOR_ID, GRANTOR_NAME, GRANTOR_TYPE, ");
selectStmt += ("PRIVILEGES_BITMAP, GRANTABLE_BITMAP FROM ");
selectStmt += tableName_;
selectStmt += " ";
selectStmt += whereClause;
selectStmt += orderByClause;
// set pointer in diags area
int32_t diagsMark = pDiags_->mark();
ExeCliInterface cliInterface(STMTHEAP, 0, NULL,
CmpCommon::context()->sqlSession()->getParentQid());
Queue * tableQueue = NULL;
int32_t cliRC = cliInterface.fetchAllRows(tableQueue, (char *)selectStmt.c_str(), 0, false, false, true);
if (cliRC < 0)
{
cliInterface.retrieveSQLDiagnostics(CmpCommon::diags());
return STATUS_ERROR;
}
if (cliRC == 100) // did not find the row
{
pDiags_->rewind(diagsMark);
return STATUS_NOTFOUND;
}
tableQueue->position();
for (int idx = 0; idx < tableQueue->numEntries(); idx++)
{
OutputInfo * pCliRow = (OutputInfo*)tableQueue->getNext();
ObjectPrivsMDRow *pRow = new ObjectPrivsMDRow();
setRow(pCliRow, *pRow);
rowList.push_back(pRow);
}
return STATUS_GOOD;
}
// *****************************************************************************
// * method: ObjectPrivsMDTable::setRow
// *
// * Create an ObjectPrivsMDRow object from the information returned from the
// * cli.
// *
// * Parameters:
// *
// * <OutputInfo> row destails from the cli
// * <rowOut> passes back the ObjectPrivsMDRow row
// *
// * no errors should be generated
// *****************************************************************************
// Row read successfully. Extract the columns.
void ObjectPrivsMDTable::setRow (OutputInfo *pCliRow,
ObjectPrivsMDRow &row)
{
char * ptr = NULL;
Int32 len = 0;
char value[500];
// column 1: object uid
pCliRow->get(0,ptr,len);
row.objectUID_ = *(reinterpret_cast<int64_t*>(ptr));
// column 2: object name
pCliRow->get(1,ptr,len);
assert (len < 257);
strncpy(value, ptr, len);
value[len] = 0;
row.objectName_ = value;
// column 3: object type
pCliRow->get(2,ptr,len);
assert (len < 3);
strncpy(value, ptr, len);
value[len] = 0;
row.objectType_ = PrivMgr::ObjectLitToEnum(value);
// column 4: grantee uid
pCliRow->get(3,ptr,len);
row.granteeID_ = *(reinterpret_cast<int32_t*>(ptr));
// column 5: grantee name
pCliRow->get(4,ptr,len);
assert (len < 257);
strncpy(value, ptr, len);
value[len] = 0;
row.granteeName_ = value;
// column 6: grantee type
pCliRow->get(5,ptr,len);
assert (len < 3);
strncpy(value, ptr, len);
value[len] = 0;
row.granteeType_ = value;
// column 7: grantor uid
pCliRow->get(6,ptr,len);
row.grantorID_ = *(reinterpret_cast<int32_t*>(ptr));
//column 8: grantor name
pCliRow->get(7,ptr,len);
assert (len < 257);
strncpy(value, ptr, len);
value[len] = 0;
row.grantorName_ = value;
//column 9: grantor type
pCliRow->get(8,ptr,len);
assert (len < 3);
strncpy(value, ptr, len);
value[len] = 0;
row.grantorType_ = value;
// column 10: privileges bitmap
pCliRow->get(9,ptr,len);
int64_t bitmapInt = *(reinterpret_cast<int64_t*>(ptr));
row.privsBitmap_ = bitmapInt;
// column 11: grantable bitmap
pCliRow->get(10,ptr,len);
bitmapInt = *(reinterpret_cast<int64_t*>(ptr));
row.grantableBitmap_ = bitmapInt;
// set current_
PrivMgrCoreDesc tempDesc (row.privsBitmap_, row.grantableBitmap_);
row.current_= tempDesc;
row.visited_.setAllPrivAndWgo(false);
}
// *****************************************************************************
// * method: ObjectPrivsMDTable::insert
// *
// * Inserts a row into the OBJECT_PRIVILEGES table.
// *
// * Parameters:
// *
// * <rowIn> is a ObjectPrivsMDRow to be inserted.
// *
// * Returns: PrivStatus
// *
// * STATUS_GOOD: Row inserted.
// * *: Insert failed. A CLI error is put into the diags area.
// *****************************************************************************
PrivStatus ObjectPrivsMDTable::insert(const PrivMgrMDRow &rowIn)
{
char insertStmt[2000];
const ObjectPrivsMDRow &row = static_cast<const ObjectPrivsMDRow &>(rowIn);
int64_t privilegesBitmapLong = row.privsBitmap_.to_ulong();
int64_t grantableBitmapLong = row.grantableBitmap_.to_ulong();
char objectTypeLit[3] = {0};
strncpy(objectTypeLit,PrivMgr::ObjectEnumToLit(row.objectType_),2);
sprintf(insertStmt, "insert into %s values (%ld, '%s', '%s', %d, '%s', '%s', %d, '%s', '%s', %ld, %ld)",
tableName_.c_str(),
row.objectUID_,
row.objectName_.c_str(),
objectTypeLit,
row.granteeID_,
row.granteeName_.c_str(),
row.granteeType_.c_str(),
row.grantorID_,
row.grantorName_.c_str(),
row.grantorType_.c_str(),
privilegesBitmapLong,
grantableBitmapLong);
ExeCliInterface cliInterface(STMTHEAP, 0, NULL,
CmpCommon::context()->sqlSession()->getParentQid());
int32_t cliRC = cliInterface.executeImmediate(insertStmt);
if (cliRC < 0)
{
cliInterface.retrieveSQLDiagnostics(pDiags_);
return STATUS_ERROR;
}
// For some reason, insert sometimes returns error even though
// the row is inserted, so unless an errors, return STATUS_GOOD
return STATUS_GOOD;
}
// *****************************************************************************
// * method: ObjectPrivsMDTable::deleteRow
// *
// * Deletes a row from the OBJECT_PRIVILEGES table based on the primary key
// * contents of the row.
// *
// * Parameters:
// *
// * <row> defines what row should be deleted
// *
// * Returns: PrivStatus
// *
// * STATUS_GOOD: Row deleted.
// * *: Insert failed. A CLI error is put into the diags area.
// *****************************************************************************
PrivStatus ObjectPrivsMDTable::deleteRow(const ObjectPrivsMDRow & row)
{
char whereClause[1000];
sprintf(whereClause," WHERE object_uid = %ld AND grantor_id = %d AND grantee_id = %d ",
row.objectUID_,row.grantorID_,row.granteeID_);
return deleteWhere(whereClause);
}
// *****************************************************************************
// * method: ObjectPrivsMDTable::deleteWhere
// *
// * Deletes a row from the OBJECT_PRIVILEGES table based on the where clause
// *
// * Parameters:
// *
// * <whereClause> defines what rows should be deleted
// *
// * Returns: PrivStatus
// *
// * STATUS_GOOD: Row(s) deleted.
// * *: Insert failed. A CLI error is put into the diags area.
// *****************************************************************************
PrivStatus ObjectPrivsMDTable::deleteWhere(const std::string & whereClause)
{
std::string deleteStmt ("DELETE FROM ");
deleteStmt += tableName_;
deleteStmt += " ";
deleteStmt += whereClause;
// set pointer in diags area
int32_t diagsMark = pDiags_->mark();
ExeCliInterface cliInterface(STMTHEAP, 0, NULL,
CmpCommon::context()->sqlSession()->getParentQid());
int32_t cliRC = cliInterface.executeImmediate(deleteStmt.c_str());
if (cliRC < 0)
{
cliInterface.retrieveSQLDiagnostics(CmpCommon::diags());
return STATUS_ERROR;
}
if (cliRC == 100) // did not find any rows
{
pDiags_->rewind(diagsMark);
return STATUS_NOTFOUND;
}
if (cliRC > 0)
return STATUS_WARNING;
return STATUS_GOOD;
}
// *****************************************************************************
// * method: ObjectPrivsMDTable::updateRow
// *
// * Updates grantor and bitmaps for a row in the OBJECT_PRIVILEGES table
// * based on the contents of the row.
// *
// * Parameters:
// *
// * <row> defines what row should be updated
// *
// * Returns: PrivStatus
// *
// * STATUS_GOOD: Row(s) deleted.
// * *: Insert failed. A CLI error is put into the diags area.
// *****************************************************************************
PrivStatus ObjectPrivsMDTable::updateRow(const ObjectPrivsMDRow & row)
{
char setClause[1000];
int64_t privilegesBitmapLong = row.privsBitmap_.to_ulong();
int64_t grantableBitmapLong = row.grantableBitmap_.to_ulong();
sprintf(setClause," SET grantor_id = %d, grantor_name = '%s', "
" privileges_bitmap = %ld, grantable_bitmap = %ld ",
row.grantorID_,row.grantorName_.c_str(),privilegesBitmapLong,grantableBitmapLong);
char whereClause[1000];
sprintf(whereClause," WHERE object_uid = %ld AND grantor_id = %d AND grantee_id = %d ",
row.objectUID_,row.grantorID_,row.granteeID_);
return updateWhere(setClause,whereClause);
}
// ----------------------------------------------------------------------------
// method: updateWhere
//
// This method updates one or more rows from the OBJECT_PRIVILEGES table
// The number of rows affected depend on the passed in set clause
//
// Input: setClause
// whereClause
// Output: status of the operation
//
// A cli error is put into the diags area if there is an error
// ----------------------------------------------------------------------------
PrivStatus ObjectPrivsMDTable::updateWhere(const std::string & setClause,
const std::string & whereClause)
{
std::string updateStmt ("UPDATE ");
updateStmt += tableName_;
updateStmt += " ";
updateStmt += setClause;
updateStmt += " ";
updateStmt += whereClause;
// set pointer in diags area
int32_t diagsMark = pDiags_->mark();
ExeCliInterface cliInterface(STMTHEAP, 0, NULL,
CmpCommon::context()->sqlSession()->getParentQid());
int32_t cliRC = cliInterface.executeImmediate(updateStmt.c_str());
if (cliRC < 0)
{
cliInterface.retrieveSQLDiagnostics(CmpCommon::diags());
return STATUS_ERROR;
}
if (cliRC == 100) // did not find any rows
{
pDiags_->rewind(diagsMark);
return STATUS_NOTFOUND;
}
if (cliRC > 0)
return STATUS_WARNING;
return STATUS_GOOD;
}
// ----------------------------------------------------------------------------
// method::insertSelect
//
// This method inserts owner rows into the OBJECT_PRIVILEGES table
//
// Input: objectsLocation - name of objects table
// authsLocation - name of auths table
//
// Output: PrivStatus
//
// the following is a sample insert select statement that gets processed:
//
// insert into OBJECT_PRIVILEGES
// select distinct
// object_uid,
// <catalogName> "<schema_name>"."<object_name>",
// object_type,
// object_owner, -- granteeID
// coalesce((select auth_db_name from AUTHS where auth_id = object_owner),
// 'DB__ROOT') --granteeName
// USER_GRANTEE_LIT, -- "U"
// SYSTEM_USER, -- system grantor ID (-2)
// SYSTEM_AUTH_NAME, -- grantorName (_SYSTEM)
// SYSTEM_GRANTOR_LIST, -- "S"
// case
// when object_type = 'BT' then 47
// when object_type = 'VI' then 1
// when object_type = 'LB' then 24
// when object_type = 'UR' then 64
// when object_type = 'SG' then 16
// else 0
// end as privilegesBitmap,
// case
// when object_type = 'BT' then 47
// when object_type = 'VI' then 0
// when object_type = 'LB' then 24
// when object_type = 'UR' then 0
// when object_type = 'SG' then 16
// else 0
// end as grantableBitmap
// from OBJECTS
// where object_type in ('VI','BT','LB','UR','SG')
//
// The "coalesce" for the granteeName above is in case the auth_id is
// invalid (that is, does not appear in the AUTHS table). If we don't
// know who the auth_id is, we'll put DB__ROOT, the super user, there.
//
// The ComDiags area is set up with unexpected errors
// ----------------------------------------------------------------------------
PrivStatus ObjectPrivsMDTable::insertSelect(
const std::string &objectsLocation,
const std::string &authsLocation)
{
// Before inserting rows, make sure that the OBJECT_PRIVILEGES table is empty
char buf[2000];
sprintf(buf, "select count(*) from %s", tableName_.c_str());
Int64 rowsSelected = 0;
Lng32 theLen = 0;
ExeCliInterface cliInterface(STMTHEAP, 0, NULL,
CmpCommon::context()->sqlSession()->getParentQid());
int32_t cliRC = cliInterface.executeImmediate(buf, (char*)&rowsSelected, &theLen, FALSE);
if (cliRC < 0)
{
cliInterface.retrieveSQLDiagnostics(CmpCommon::diags());
return STATUS_ERROR;
}
if (rowsSelected != 0)
{
std::string message ("Found ");
message += to_string((long long int)rowsSelected);
message += " rows in OBJECT_PRIVILEGES table, expecting 0 rows";
PRIVMGR_INTERNAL_ERROR(message.c_str());
return STATUS_ERROR;
}
// Create bitmaps for all supported object types;
PrivMgrDesc privDesc;
privDesc.setAllTableGrantPrivileges(true);
int64_t tableBits = privDesc.getTablePrivs().getPrivBitmap().to_ulong();
privDesc.setAllLibraryGrantPrivileges(true);
int64_t libraryBits = privDesc.getTablePrivs().getPrivBitmap().to_ulong();
privDesc.setAllUdrGrantPrivileges(true);
int64_t udrBits = privDesc.getTablePrivs().getPrivBitmap().to_ulong();
privDesc.setAllSequenceGrantPrivileges(true);
int64_t sequenceBits = privDesc.getTablePrivs().getPrivBitmap().to_ulong();
// for views, privilegesBitmap is set to 1 (SELECT), wgo to 0 (no)
std::string systemGrantor(SYSTEM_AUTH_NAME);
// Generate case stmt for grantable bitmap
sprintf (buf, "case when object_type = 'BT' then %ld "
" when object_type = 'VI' then 1 "
" when object_type = 'LB' then %ld "
" when object_type = 'UR' then %ld "
" when object_type = 'SG' then %ld "
" else 0 end",
tableBits, libraryBits, udrBits, sequenceBits);
std::string privilegesClause(buf);
sprintf (buf, "case when object_type = 'BT' then %ld "
" when object_type = 'VI' then 0 "
" when object_type = 'LB' then %ld "
" when object_type = 'UR' then %ld "
" when object_type = 'SG' then %ld "
" else 0 end",
tableBits, libraryBits, udrBits, sequenceBits);
std::string grantableClause(buf);
sprintf(buf, "insert into %s select distinct object_uid, "
"trim(catalog_name) || '.\"' || trim(schema_name) || '\".\"' || trim(object_name) || '\"', "
"object_type, object_owner, "
"coalesce((select auth_db_name from %s where auth_id = o.object_owner),'DB__ROOT') as auth_db_name, "
"'%s', %d, '%s', '%s', %s, %s from %s o "
"where o.object_type in ('VI','BT','LB','UR','SG')",
tableName_.c_str(),
authsLocation.c_str(),
USER_GRANTEE_LIT,
SYSTEM_USER, SYSTEM_AUTH_NAME, SYSTEM_GRANTOR_LIT,
privilegesClause.c_str(), grantableClause.c_str(),
objectsLocation.c_str());
// set pointer in diags area
int32_t diagsMark = pDiags_->mark();
Int64 rowsInserted = 0;
cliRC = cliInterface.executeImmediate(buf, NULL, NULL, FALSE, &rowsInserted);
if (cliRC < 0)
{
cliInterface.retrieveSQLDiagnostics(CmpCommon::diags());
return STATUS_ERROR;
}
// Bug: for some reasons, insert returns NOTFOUND even though the
// operations succeeded.
if (cliRC == 100)
{
pDiags_->rewind(diagsMark);
cliRC = 0;
}
// Make sure rows were inserted correctly.
// Get the expected number of rows
sprintf(buf, "select count(*) from %s o where o.object_type in ('VI','BT','LB','UR', 'SG')"
" and object_owner > 0",
objectsLocation.c_str());
Lng32 len = 0;
cliRC = cliInterface.executeImmediate(buf, (char*)&rowsSelected, &len, FALSE);
if (cliRC < 0)
{
cliInterface.retrieveSQLDiagnostics(CmpCommon::diags());
return STATUS_ERROR;
}
// Check to see if the number of rows selected match the rows inserted
if (rowsInserted != rowsSelected)
{
std::string message ("Expected to insert ");
message += to_string((long long int)rowsSelected);
message += " rows into OBJECT_PRIVILEGES table, instead ";
message += to_string((long long int)rowsInserted);
message += " were found.";
PRIVMGR_INTERNAL_ERROR(message.c_str());
return STATUS_ERROR;
}
return STATUS_GOOD;
}
// ----------------------------------------------------------------------------
// method::insertSelect
//
// This method inserts a grant of SELECT on the AUTHS table to PUBLIC
// into the OBJECT_PRIVILEGES table
//
// Input: objectsLocation - name of objects table
// authsLocation - name of auths table
//
// Output: PrivStatus
//
// The ComDiags area is set up with unexpected errors
// ----------------------------------------------------------------------------
PrivStatus ObjectPrivsMDTable::insertSelectOnAuthsToPublic(
const std::string &objectsLocation,
const std::string &authsLocation)
{
char buf[2000];
sprintf(buf, "insert into %s select o.object_uid,'%s','BT',-1,'PUBLIC','U',"
"%d,'DB__ROOT','U',1,0 FROM %s O WHERE O.OBJECT_NAME = 'AUTHS'",
tableName_.c_str(),authsLocation.c_str(), MIN_USERID, objectsLocation.c_str());
// set pointer in diags area
int32_t diagsMark = pDiags_->mark();
Int64 rowsInserted = 0;
ExeCliInterface cliInterface(STMTHEAP, NULL, NULL,
CmpCommon::context()->sqlSession()->getParentQid());
int32_t cliRC = cliInterface.executeImmediate(buf, NULL, NULL, FALSE, &rowsInserted);
if (cliRC < 0)
{
cliInterface.retrieveSQLDiagnostics(CmpCommon::diags());
return STATUS_ERROR;
}
// Bug: for some reasons, insert returns NOTFOUND even though the
// operations succeeded.
if (cliRC == 100)
{
pDiags_->rewind(diagsMark);
cliRC = 0;
}
return STATUS_GOOD;
}
// *****************************************************************************
// ColumnPrivsMDRow methods
// *****************************************************************************
void ColumnPrivsMDRow::describeRow (std::string &rowDetails)
{
rowDetails = "COLUMN_PRIVILEGES row: UID is ";
rowDetails += to_string((long long int) objectUID_);
rowDetails += ", column number is ";
rowDetails += to_string((long long int) columnOrdinal_);
rowDetails += ", grantor is ";
rowDetails += to_string((long long int)grantorID_);
rowDetails += ", grantee is ";
rowDetails += to_string((long long int) granteeID_);
}
// *****************************************************************************
// ColumnPrivsMDTable methods
// *****************************************************************************
// *****************************************************************************
// * *
// * Function: ColumnPrivsMDTable::insert *
// * *
// * Inserts a row into the COLUMN_PRIVILEGES table. *
// * *
// *****************************************************************************
// * *
// * Parameters: *
// * *
// * <rowIn> const PrivMgrMDRow & In *
// * is a ColumnPrivsMDRow to be inserted. *
// * *
// *****************************************************************************
// * *
// * Returns: PrivStatus *
// * *
// * STATUS_GOOD: Row inserted. *
// * *: Insert failed. A CLI error is put into the diags area. *
// * *
// *****************************************************************************
PrivStatus ColumnPrivsMDTable::insert(const PrivMgrMDRow &rowIn)
{
char insertStmt[2000];
const ColumnPrivsMDRow &row = static_cast<const ColumnPrivsMDRow &>(rowIn);
int64_t privilegesBitmapLong = row.privsBitmap_.to_ulong();
int64_t grantableBitmapLong = row.grantableBitmap_.to_ulong();
sprintf(insertStmt, "INSERT INTO %s VALUES (%ld, '%s', %d, '%s', %d, '%s', %d, %ld, %ld)",
tableName_.c_str(),
row.objectUID_,
row.objectName_.c_str(),
row.granteeID_,
row.granteeName_.c_str(),
row.grantorID_,
row.grantorName_.c_str(),
row.columnOrdinal_,
privilegesBitmapLong,
grantableBitmapLong);
return CLIImmediate(insertStmt);
}
//********************* End of ColumnPrivsMDTable::insert **********************
// *****************************************************************************
// * *
// * Function: ColumnPrivsMDTable::selectWhere *
// * *
// * Selects rows from the COLUMN_PRIVILEGES table based on the specified *
// * WHERE clause. Output is sorted by grantor, grantee, column in that order.*
// * *
// *****************************************************************************
// * *
// * Parameters: *
// * *
// * <whereClause> const std::string & In *
// * is the WHERE clause specifying a unique row. *
// * *
// * <orderByClause> is the ORDER BY clause defining returned row order.
// * <rowList> std::vector<PrivMgrMDRow *> & Out *
// * passes back a set of ColumnPrivsMDRow rows. *
// * *
// *****************************************************************************
// * *
// * Returns: PrivStatus *
// * *
// * STATUS_GOOD: Rows returned. *
// * *: Select failed. A CLI error is put into the diags area. *
// * *
// *****************************************************************************
PrivStatus ColumnPrivsMDTable::selectWhere(
const std::string & whereClause,
const std::string & orderByClause,
std::vector<PrivMgrMDRow *> &rowList)
{
std::string selectStmt("SELECT object_uid,object_name,"
"grantee_id,grantee_name,"
"grantor_id,grantor_name,column_number,"
"privileges_bitmap,grantable_bitmap FROM ");
selectStmt += tableName_ + " ";
selectStmt += whereClause + orderByClause;
// set pointer in diags area
int32_t diagsMark = pDiags_->mark();
ExeCliInterface cliInterface(STMTHEAP);
Queue * tableQueue = NULL;
int32_t cliRC = cliInterface.fetchAllRows(tableQueue, (char *)selectStmt.c_str(), 0, false, false, true);
if (cliRC < 0)
{
cliInterface.retrieveSQLDiagnostics(CmpCommon::diags());
return STATUS_ERROR;
}
if (cliRC == 100) // did not find the row
{
pDiags_->rewind(diagsMark);
return STATUS_NOTFOUND;
}
tableQueue->position();
for (int idx = 0; idx < tableQueue->numEntries(); idx++)
{
OutputInfo * pCliRow = (OutputInfo*)tableQueue->getNext();
ColumnPrivsMDRow *pRow = new ColumnPrivsMDRow();
setRow(pCliRow,*pRow);
rowList.push_back(pRow);
}
return STATUS_GOOD;
}
//****************** End of ColumnPrivsMDTable::selectWhere ********************
// *****************************************************************************
// * *
// * Function: ColumnPrivsMDTable::selectWhereUnique *
// * *
// * Selects a row from the COLUMN_PRIVILEGES table based on the specified *
// * WHERE clause. *
// * *
// *****************************************************************************
// * *
// * Parameters: *
// * *
// * <whereClause> const std::string & In *
// * is the WHERE clause specifying a unique row. *
// * *
// * <row> PrivMgrMDRow & Out *
// * passes back a ColumnPrivsMDRow row. *
// * *
// *****************************************************************************
// * *
// * Returns: PrivStatus *
// * *
// * STATUS_GOOD: Row returned. *
// * *: Select failed. A CLI error is put into the diags area. *
// * *
// *****************************************************************************
PrivStatus ColumnPrivsMDTable::selectWhereUnique(
const std::string & whereClause,
PrivMgrMDRow & row)
{
//TODO: Currently unused. Added due to virtual declaration. Will be fleshed
// out when run-time column privilege checking added.
return STATUS_GOOD;
}
//************** End of ColumnPrivsMDTable::selectWhereUnique ******************
// *****************************************************************************
// * *
// * Function: MyTable::setRow *
// * *
// * Create a ColumnPrivsMDRow object from the information returned from the
// * CLI.
// * *
// *****************************************************************************
// * *
// * Parameters: *
// * *
// * <pCliRow> OutputInfo & In *
// * is a pointer to the CLI interface to the row data that was read. *
// * *
// * <row> PrivMgrMDRow & Out *
// * passes back a ColumnPrivsMDRow. *
// * *
// *****************************************************************************
void ColumnPrivsMDTable::setRow(
OutputInfo *pCliRow,
ColumnPrivsMDRow &row)
{
char * ptr = NULL;
Int32 len = 0;
char value[500];
// column 0: object uid
pCliRow->get(0,ptr,len);
row.objectUID_ = *(reinterpret_cast<int64_t*>(ptr));
// column 1: object name
pCliRow->get(1,ptr,len);
assert (len < 257);
strncpy(value, ptr, len);
value[len] = 0;
row.objectName_ = value;
// column 2: grantee id
pCliRow->get(2,ptr,len);
row.granteeID_ = *(reinterpret_cast<int32_t*>(ptr));
// column 3: grantee name
pCliRow->get(3,ptr,len);
assert (len < 257);
strncpy(value, ptr, len);
value[len] = 0;
row.granteeName_ = value;
// column 4: grantor id
pCliRow->get(4,ptr,len);
row.grantorID_ = *(reinterpret_cast<int32_t*>(ptr));
// column 5: grantor name
pCliRow->get(5,ptr,len);
assert (len < 257);
strncpy(value, ptr, len);
value[len] = 0;
row.grantorName_ = value;
// column 6: column_number
pCliRow->get(6,ptr,len);
row.columnOrdinal_ = *(reinterpret_cast<int32_t*>(ptr));
// column 7: privileges bitmap
pCliRow->get(7,ptr,len);
int64_t bitmapInt = *(reinterpret_cast<int64_t*>(ptr));
row.privsBitmap_ = bitmapInt;
// column 8: grantable bitmap
pCliRow->get(8,ptr,len);
bitmapInt = *(reinterpret_cast<int64_t*>(ptr));
row.grantableBitmap_ = bitmapInt;
}
//******************* End of ColumnPrivsMDTable::setRow ************************
// *****************************************************************************
// * *
// * Function: ColumnPrivsMDTable::updateRow *
// * *
// * Updates the bitmaps for a row in the COLUMN_PRIVILEGES table based on *
// * the contents of the row. *
// * *
// *****************************************************************************
// * *
// * Parameters: *
// * *
// * <row> PrivMgrMDRow & In *
// * is the row to be updated. *
// * *
// * <whereBase> const std::string & In *
// * is the WHERE clause specifying the primary keys except for the *
// * column number, which is added within this function. *
// * *
// *****************************************************************************
// * *
// * Returns: PrivStatus *
// * *
// * STATUS_GOOD: Row returned. *
// * *: Select failed. A CLI error is put into the diags area. *
// * *
// *****************************************************************************
PrivStatus ColumnPrivsMDTable::updateColumnRow(
const ColumnPrivsMDRow & row,
const std::string whereBase)
{
char setClause[1000];
int64_t privilegesBitmapLong = row.privsBitmap_.to_ulong();
int64_t grantableBitmapLong = row.grantableBitmap_.to_ulong();
sprintf(setClause," SET privileges_bitmap = %ld, grantable_bitmap = %ld ",
privilegesBitmapLong,grantableBitmapLong);
char whereClause[1000];
sprintf(whereClause," %s %d",whereBase.c_str(),row.columnOrdinal_);
return updateWhere(setClause,whereClause);
}
//*************** End of ColumnPrivsMDTable::updateColumnRow *******************