blob: 882ce93bc532001f08136eccd45384edc0475d82 [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 "PrivMgrRoles.h"
#include "PrivMgrMD.h"
#include "PrivMgrMDTable.h"
#include "PrivMgrObjects.h"
#include "PrivMgrPrivileges.h"
#include <string>
#include <cstdio>
#include <vector>
#include "ComSmallDefs.h"
// sqlcli.h included because ExExeUtilCli.h needs it (and does not include it!)
#include "sqlcli.h"
#include "ExExeUtilCli.h"
#include "ComDiags.h"
#include "ComQueue.h"
// CmpCommon.h contains STMTHEAP declaration
#include "CmpCommon.h"
#include "CmpDDLCatErrorCodes.h"
#include "NAUserId.h"
#include "ComUser.h"
#include "ComSecurityKey.h"
static bool hasValue(
std::vector<int32_t> container,
int32_t value);
static bool isDependentObjectPrivPair(
ComObjectType objectType,
PrivMgrBitmap objectPrivs);
namespace Roles
{
// *****************************************************************************
// * Class: MyRow
// * Description: This class represents a row in the ROLE_USAGE table.
// *****************************************************************************
class MyRow : public PrivMgrMDRow
{
public:
// -------------------------------------------------------------------
// Constructors and destructors:
// -------------------------------------------------------------------
MyRow(std::string tableName)
: PrivMgrMDRow(tableName, ROLE_USAGES_ENUM),
roleID_(0)
{ };
MyRow(const MyRow &other)
: PrivMgrMDRow(other)
{
roleID_ = other.roleID_;
roleName_ = other.roleName_;
granteeID_ = other.granteeID_;
granteeName_ = other.granteeName_;
granteeAuthClass_ = other.granteeAuthClass_;
grantorID_ = other.grantorID_;
grantorName_ = other.grantorName_;
grantorAuthClass_ = other.grantorAuthClass_;
grantDepth_ = other.grantDepth_;
};
virtual ~MyRow() {};
// -------------------------------------------------------------------
// Data Members:
// -------------------------------------------------------------------
// From ROLE_USAGE
int32_t roleID_;
std::string roleName_;
int32_t granteeID_;
std::string granteeName_;
PrivAuthClass granteeAuthClass_;
int32_t grantorID_;
std::string grantorName_;
PrivAuthClass grantorAuthClass_;
int32_t grantDepth_;
private:
MyRow();
};
// *****************************************************************************
// * Class: MyTable
// * Description: This class represents the ROLE_USAGE table.
// *
// *****************************************************************************
class MyTable : public PrivMgrMDTable
{
public:
MyTable(
const std::string & tableName,
ComDiagsArea * pDiags = NULL)
: PrivMgrMDTable(tableName,ROLE_USAGES_ENUM, pDiags),
lastRowRead_(tableName)
{};
virtual PrivStatus insert(const PrivMgrMDRow &row);
PrivStatus insertSelect(
const std::string & authsLocation,
const std::string & inClause);
PrivStatus selectAllWhere(
const std::string & whereClause,
const std::string & orderByClause,
std::vector<MyRow> & rows);
virtual PrivStatus selectWhereUnique(
const std::string & whereClause,
PrivMgrMDRow & row);
void setRow(
OutputInfo &cliInterface,
PrivMgrMDRow &rowOut);
private:
MyTable();
MyRow lastRowRead_;
};
}//End namespace Roles
using namespace Roles;
// *****************************************************************************
// PrivMgrRoles methods
// *****************************************************************************
// -----------------------------------------------------------------------
// Construct a PrivMgrRoles object
// -----------------------------------------------------------------------
PrivMgrRoles::PrivMgrRoles(
const std::string & trafMetadataLocation,
const std::string & metadataLocation,
ComDiagsArea * pDiags)
: PrivMgr(trafMetadataLocation,metadataLocation,pDiags),
fullTableName_(metadataLocation_ + ".ROLE_USAGE"),
myTable_(*new MyTable(fullTableName_,pDiags))
{ };
// -----------------------------------------------------------------------
// Copy constructor
// -----------------------------------------------------------------------
PrivMgrRoles::PrivMgrRoles(const PrivMgrRoles &other)
: PrivMgr(other),
myTable_(*new MyTable(fullTableName_,pDiags_))
{
fullTableName_ = other.fullTableName_;
}
// -----------------------------------------------------------------------
// Destructor.
// -----------------------------------------------------------------------
PrivMgrRoles::~PrivMgrRoles()
{
delete &myTable_;
}
// *****************************************************************************
// * *
// * Function: PrivMgrRoles::areRemainingGrantedPrivsSufficient *
// * *
// * Determines if a set (possibly empty) of granted privileges contains *
// * the specified privilege. *
// * *
// *****************************************************************************
// * *
// * Parameters: *
// * *
// * <whereClause> const std::string & In *
// * is the WHERE clause specifying the set of privileges. *
// * *
// * <privType> PrivType In *
// * is the type of privilege that is needed. *
// * *
// *****************************************************************************
// * *
// * Returns: bool *
// * *
// * true: Privilege was found. *
// * false: Privilege not found, or internal error occured. *
// * *
// *****************************************************************************
bool PrivMgrRoles::areRemainingGrantedPrivsSufficient(
const std::string whereClause,
PrivType privType)
{
std::vector<PrivMgrBitmap> privBitmaps;
std::string orderByClause;
PrivMgrPrivileges objectPrivileges(metadataLocation_,pDiags_);
PrivStatus privStatus = objectPrivileges.getPrivBitmaps(whereClause,
orderByClause,
privBitmaps);
//TODO: instead of a vector of bitmaps, could get union of bitmaps.
// If no rows match the criteria, that means the user does not
// have privileges on this referenced object, so they can no
// longer create the view after losing privileges from role.
if (privStatus == STATUS_NOTFOUND)
return false;
if (privStatus == STATUS_ERROR)
{
PRIVMGR_INTERNAL_ERROR("Could not fetch privileges for referenced objects");
return false;
}
// User has one or more privileges granted on the referenced object. At least
// one of the granted privileges has to include the specified priv type.
for (size_t pb = 0; pb < privBitmaps.size(); pb++)
if (privBitmaps[pb].test(privType))
return true;
// Priv not found among remaining granted privileges.
return false;
}
//********* End of PrivMgrRoles::areRemainingGrantedPrivsSufficient ************
// *****************************************************************************
// * *
// * Function: PrivMgrRoles::dependentObjectsExist *
// * *
// * Determines if a specific user owns objects whose existence depend upon *
// * a privilege granted to the specified role. Used to determine if a role *
// * can be revoked from a user without consequence. *
// * *
// *****************************************************************************
// * *
// * Parameters: *
// * *
// * <userID> const int32_t In *
// * is the authorization ID of the user. *
// * *
// * <roleID> const int32_t In *
// * is the role ID. *
// * *
// * <dropBehavior> PrivDropBehavior In *
// * indicates whether restrict or cascade behavior is requested. *
// * *
// *****************************************************************************
// * *
// * Returns: bool *
// * *
// * true: One or more objects exist due to grants to role, or internal error. *
// * false: No user objects are dependent on privileges granted to this role. *
// * *
// *****************************************************************************
bool PrivMgrRoles::dependentObjectsExist(
const int32_t userID,
const int32_t roleID,
PrivDropBehavior dropBehavior)
{
// First, determine if the role has been granted any object privileges.
// Only REFERENCES, SELECT and USAGE are relevant, but for now check all DML.
// If no granted privileges, then there are no objects created by this user
// depending on privileges granted to this role.
std::vector<PrivClass> privClass;
privClass.push_back(PrivClass::OBJECT);
std::vector<int64_t> objectUIDs;
if (!isAuthIDGrantedPrivs(roleID,privClass, objectUIDs))
return false;
// Second, see if the user owns any objects that are dependent, i.e., views,
// referential integrity (RI) constraints, or UDFs/SPJs.
std::string whereClause(" WHERE OBJECT_TYPE IN ('RC','SP','UR','VI') AND OBJECT_OWNER = ");
whereClause += authIDToString(userID);
PrivMgrObjects objects(trafMetadataLocation_,pDiags_);
std::vector<UIDAndType> ownedUIDandTypes;
PrivStatus privStatus = objects.fetchUIDandTypes(whereClause,ownedUIDandTypes);
if (privStatus == STATUS_ERROR)
{
PRIVMGR_INTERNAL_ERROR("Could not fetch objects owned by user");
return true;
}
// If the user does not own any views, user defined functions, or referential
// integrity constraints, they do not have any dependent objects.
if (privStatus == STATUS_NOTFOUND || ownedUIDandTypes.size() == 0)
return false;
//TODO: User owns dependent objects and role has been granted privileges.
// But do they correlate? For instance, if a role is granted INSERT,
// losing that privilege does not affect any views the user may own.
// Could get list of privilege types granted the role, and then
// compare with types of dependent objects. If no correlation,
// short-circuit this check. See file private function
// isDependentObjectPrivPair().
// OK, user owns dependent objects and role has been granted privileges.
// One of more of those objects could depend on privileges granted this role.
// Get the name of the role to use in error messages.
int32_t length;
char roleName[MAX_DBUSERNAME_LEN + 1];
Int16 retCode = ComUser::getAuthNameFromAuthID(roleID,roleName,
sizeof(roleName),length);
// Should not fail, role ID was derived from name provided by user.
if (retCode != 0)
{
std::string errorText("Unable to look up role name for role ID ");
errorText += authIDToString(roleID);
PRIVMGR_INTERNAL_ERROR(errorText.c_str());
return true;
}
// For each owned object, get the objects that the owned objects reference.
// Determine if the user has the requisite privilege on each of the
// referenced objects if the privileges granted to the role are not included.
// If the user has the privilege (either directly or through another role),
// move on to the next referenced object, and then on to the next owned object.
// If any dependency on a privilege granted to this role is found, it is an
// error if the behavior is restrict. For cascade (not yet supported), the
// dependent object is automatically dropped.
// For each referenced object, get privileges the user has on that object
// either directly or by another role granted to the user, but exclude
// any privileges from the role being revoked. The first part of the query
// can be built once, and the object UID for each referenced object added
// within the loop.
//
// WHERE (GRANTEE_ID = -1 OR GRANTEE_ID = userID OR
// GRANTEE_ID IN (SELECT ROLE_ID FROM ROLE_USAGE WHERE GRANTEE_ID = userID)) AND
// GRANTEE_ID <> roleID AND OBJECT_UID = objectUID;
std::string whereClauseHeader(" WHERE (GRANTEE_ID = -1 OR GRANTEE_ID = ");
whereClauseHeader += authIDToString(userID);
whereClauseHeader += " OR GRANTEE_ID IN (SELECT RU.ROLE_ID FROM ";
whereClauseHeader += metadataLocation_;
whereClauseHeader += ".ROLE_USAGE RU WHERE RU.GRANTEE_ID = ";
whereClauseHeader += authIDToString(userID);
whereClauseHeader += ")) AND GRANTEE_ID <> ";
whereClauseHeader += authIDToString(roleID);
whereClauseHeader += " AND OBJECT_UID = ";
//TODO: When support is added for schema and column privileges, will need to
// check those privileges as well.
// Assume no dependencies exist.
bool dependencyFound = false;
PrivMgrMDAdmin admin(trafMetadataLocation_,metadataLocation_,pDiags_);
for (size_t u3 = 0; u3 < ownedUIDandTypes.size(); u3++)
{
std::string referencedObjectName;
// Initialize the where clause each time through the loop.
switch (ownedUIDandTypes[u3].objectType)
{
case COM_VIEW_OBJECT:
{
std::string whereClause(whereClauseHeader);
ViewUsage viewUsage;
viewUsage.viewUID = ownedUIDandTypes[u3].UID;
// Get list of objects referenced by the view. If list cannot be
// retrieved or is empty, there is a metadata inconsistency.
std::vector<ObjectReference *> referencedObjectsList;
privStatus = admin.getObjectsThatViewReferences(viewUsage,referencedObjectsList);
if (privStatus == STATUS_ERROR || privStatus == STATUS_NOTFOUND ||
referencedObjectsList.size() == 0)
{
PRIVMGR_INTERNAL_ERROR("Could not fetch objects referenced by view");
return true;
}
for (size_t obj = 0; obj < referencedObjectsList.size(); obj++)
{
whereClause = whereClauseHeader +
UIDToString(referencedObjectsList[obj]->objectUID);
PrivType privType = ALL_PRIVS;
switch (referencedObjectsList[obj]->objectType)
{
case COM_BASE_TABLE_OBJECT:
case COM_VIEW_OBJECT:
privType = SELECT_PRIV;
break;
case COM_USER_DEFINED_ROUTINE_OBJECT:
privType = EXECUTE_PRIV;
break;
default:
PRIVMGR_INTERNAL_ERROR("Unrecognized PrivType");
return true;
}
// If the user still has the requesite privilege on the referenced
// object without this role, the user is not dependent on the role's
// privileges in order to create and therefore retain this object.
if (areRemainingGrantedPrivsSufficient(whereClause,privType))
continue;
//TODO: for cascade, drop the object instead of reporting dependency error.
// for CASCADE, need to handle case where views in this list
// no longer exist because a previous referenced object resulted
// in the referencing object being dropped. Could short-circuit
// at beginning of for loop.
//
// if (objectUID not found) continue;
//
// Likewise, object referenced by this view may no longer
// exist. Example: referencing view references a table and view
// that the references the table.
privStatus = objects.fetchQualifiedName(referencedObjectsList[obj]->objectUID,
referencedObjectName);
if (privStatus != STATUS_GOOD)
{
PRIVMGR_INTERNAL_ERROR("Could not fetch name of referenced object");
return true;
}
dependencyFound = true;
break;
}
break;
}
case COM_USER_DEFINED_ROUTINE_OBJECT:
case COM_STORED_PROCEDURE_OBJECT:
{
// For user-defined routines and stored procedures, a library
// is used to represent the code. The owner needs to have the
// USAGE privileged on the referenced library. The UID of the
// library is found in the LIBRARIES_USAGE table.
std::string selectSubClause(" (SELECT USING_LIBRARY_UID FROM ");
selectSubClause += trafMetadataLocation_ + ".";
selectSubClause += SEABASE_LIBRARIES_USAGE;
selectSubClause += " WHERE USED_UDR_UID = ";
selectSubClause += UIDToString(ownedUIDandTypes[u3].UID);
selectSubClause += ")";
// If the user still has the USAGE privilage on the library without
// this role, the user is not dependent on the role's privileges
// for this UDR/SPJ.
if (areRemainingGrantedPrivsSufficient(whereClauseHeader + selectSubClause,USAGE_PRIV))
continue;
//TODO: for cascade, drop the object instead of reporting dependency error
selectSubClause.insert(0," WHERE OBJECT_UID = ");
privStatus = objects.fetchQualifiedName(selectSubClause,
referencedObjectName);
if (privStatus != STATUS_GOOD)
{
PRIVMGR_INTERNAL_ERROR("Could not fetch name of referenced object");
return true;
}
dependencyFound = true;
break;
}
case COM_REFERENTIAL_CONSTRAINT_OBJECT:
{
// For referential integrity (aka foreign) constraints, the
// constraint is associated with a refering table, but the
// REFERENCES privilege is on the referenced table. To get the
// referenced table, use the RI/Foreign contraint UID to
// obtain the unique contraint UID from the
// UNIQUE_REF_CONSTR_USAGE table. Then use that UID to find the
// UID of the referenced table from the TABLE_CONSTRAINTS table.
//
// i.e., the desired object_UID is at:
//
// (SELECT TC.TABLE_UID FROM TABLE_CONSTRAINTS TC
// WHERE TC.CONSTRAINT_UID =
// (SELECT DISTINCT RCU.UNIQUE_CONSTRAINT_UID FROM UNIQUE_REF_CONSTR_USAGE RCU
// WHERE RCU.FOREIGN_CONSTRAINT_UID = ownedConstraintUID))
//
std::string selectSubClause(" (SELECT TC.TABLE_UID FROM ");
selectSubClause += trafMetadataLocation_ + ".";
selectSubClause += SEABASE_TABLE_CONSTRAINTS;
selectSubClause += " TC WHERE TC.CONSTRAINT_UID = (SELECT DISTINCT RCU.UNIQUE_CONSTRAINT_UID FROM ";
selectSubClause += trafMetadataLocation_ + ".";
selectSubClause += SEABASE_UNIQUE_REF_CONSTR_USAGE;
selectSubClause += " RCU WHERE RCU.FOREIGN_CONSTRAINT_UID = ";
selectSubClause += UIDToString(ownedUIDandTypes[u3].UID);
selectSubClause += "))";
// If the user still has privileges on the referenced table without
// this role, the user is not dependent on the role's privileges
// for this RI constraint.
if (areRemainingGrantedPrivsSufficient(whereClauseHeader + selectSubClause,REFERENCES_PRIV))
continue;
//TODO: for cascade, drop the object instead of reporting dependency error
selectSubClause.insert(0," WHERE OBJECT_UID = ");
privStatus = objects.fetchQualifiedName(selectSubClause,
referencedObjectName);
if (privStatus != STATUS_GOOD)
{
PRIVMGR_INTERNAL_ERROR("Could not fetch name of referenced object");
return true;
}
dependencyFound = true;
break;
}
default:
{
PRIVMGR_INTERNAL_ERROR("Switch statement in PrivMgrRoles::dependentObjectsExist");
return true;
}
}
if (dependencyFound)
{
// Get name of dependent object.
std::string dependentObjectName;
privStatus = objects.fetchQualifiedName(ownedUIDandTypes[u3].UID,
dependentObjectName);
if (privStatus != STATUS_GOOD)
{
PRIVMGR_INTERNAL_ERROR("Could not fetch name of dependent object");
return true;
}
*pDiags_ << DgSqlCode(-CAT_DEPENDENT_ROLE_PRIVILEGES_EXIST)
<< DgString0(roleName)
<< DgString1(dependentObjectName.c_str())
<< DgString2(referencedObjectName.c_str());
return true;
}
}
return false;
}
//**************** End of PrivMgrRoles::dependentObjectsExist ******************
// *****************************************************************************
// * *
// * Function: PrivMgrRoles::fetchRolesForUser *
// * *
// * Returns all unique roles granted to an authorization ID. If a role is *
// * granted more than once, it is only returned one time. If one or more of *
// * the grants was WITH ADMIN OPTION, the grantDepth will reflect that. *
// * Therefore, a grant depth of zero means none of the grants of the role to *
// * the authorization ID included WITH GRANT OPTION and the auth ID cannot *
// * grant the role. *
// * *
// *****************************************************************************
// * *
// * Parameters: *
// * *
// * <authID> const int32_t In *
// * is the authorization ID whose roles are to be fetched. *
// * *
// * <roleNames> std::vector<std::string> & Out *
// * passes back a list of the names of roles granted to the *
// * authorization ID. *
// * *
// * <roleIDs> std::vector<int32_t> & Out *
// * passes back a list of role IDs granted to the authorization ID. *
// * *
// * <grantDepths> std::vector<int32_t> & Out *
// * passes back a list of grantDepths corresponding to roleNames and IDs. *
// * *
// *****************************************************************************
// * *
// * Returns: PrivStatus *
// * *
// * STATUS_GOOD: Grants for authorization ID were returned. *
// * *: Grants for authorization ID were not returned due to SQL *
// * error. The error is put into the diags area. *
// * *
// *****************************************************************************
PrivStatus PrivMgrRoles::fetchRolesForUser(
const int32_t authID,
std::vector<std::string> & roleNames,
std::vector<int32_t> & roleIDs,
std::vector<int32_t> & grantDepths)
{
std::string whereClause(" WHERE GRANTEE_ID = ");
whereClause += authIDToString(authID);
std::vector<MyRow> rows;
MyTable &myTable = static_cast<MyTable &>(myTable_);
std::string orderByClause(" ORDER BY ROLE_ID");
PrivStatus privStatus = myTable.selectAllWhere(whereClause,orderByClause,rows);
if (privStatus != STATUS_GOOD && privStatus != STATUS_WARNING)
return privStatus;
for (size_t r = 0; r < rows.size(); r++)
{
MyRow &row = rows[r];
if (hasValue(roleIDs,row.roleID_))
{
if (grantDepths.back() == 0)
grantDepths.back() = row.grantDepth_;
continue;
}
roleNames.push_back(row.granteeName_);
roleIDs.push_back(row.roleID_);
grantDepths.push_back(row.grantDepth_);
}
return STATUS_GOOD;
}
//****************** End of PrivMgrRoles::fetchRolesForUser ********************
// *****************************************************************************
// * *
// * Function: PrivMgrRoles::fetchUsersForRole *
// * *
// * Returns all grantees of a role. *
// * *
// *****************************************************************************
// * *
// * Parameters: *
// * *
// * <roleID> const int32_t In *
// * is the role ID. *
// * *
// * <granteeNames> std::vector<std::string> & Out *
// * passes back a list of names of grantees for a role. *
// * *
// * <grantorIDs> std::vector<int32_t> & Out *
// * passes back a list of grantorIDs corresponding to granteeNames. *
// * *
// * <grantDepths> std::vector<int32_t> & Out *
// * passes back a list of grantDepths corresponding to granteeNames. *
// * *
// *****************************************************************************
// * *
// * Returns: PrivStatus *
// * *
// * STATUS_GOOD: Grants for role were returned. *
// * *: Grants for roles were not returned due to SQL error. *
// * A CLI error is put into the diags area. *
// * *
// *****************************************************************************
PrivStatus PrivMgrRoles::fetchUsersForRole(
const int32_t roleID,
std::vector<std::string> & granteeNames,
std::vector<int32_t> & grantorIDs,
std::vector<int32_t> & grantDepths)
{
std::string whereClause(" WHERE ROLE_ID = ");
whereClause += authIDToString(roleID);
std::vector<MyRow> rows;
MyTable &myTable = static_cast<MyTable &>(myTable_);
std::string orderByClause(" ORDER BY GRANTEE_NAME");
PrivStatus privStatus = myTable.selectAllWhere(whereClause,orderByClause,rows);
if (privStatus != STATUS_GOOD && privStatus != STATUS_WARNING)
return privStatus;
for (size_t r = 0; r < rows.size(); r++)
{
MyRow &row = rows[r];
granteeNames.push_back(row.granteeName_);
grantorIDs.push_back(row.grantorID_);
grantDepths.push_back(row.grantDepth_);
}
return STATUS_GOOD;
}
//****************** End of PrivMgrRoles::fetchUsersForRole ********************
// *****************************************************************************
// * *
// * Function: PrivMgrRoles::fetchUsersForRoles *
// * *
// * Returns all users granted the list of roles *
// * *
// *****************************************************************************
// * *
// * Parameters: *
// * *
// * <roleIDs> const std::vector<int32_t> & In *
// * is a list of roles. *
// * *
// * <userIDs> std::vector<std::int32_t> & Out *
// * passes back a list of user grantees for the roles. *
// * *
// *****************************************************************************
// * *
// * Returns: PrivStatus *
// * *
// * STATUS_GOOD: Zero or more userIDs were returned *
// * *: Grants for roles were not returned due to SQL error. *
// * A CLI error is put into the diags area. *
// * *
// *****************************************************************************
PrivStatus PrivMgrRoles::fetchUsersForRoles(
const std::vector<int32_t> & userIDs,
std::vector<std::int32_t> & granteeIDs)
{
std::string whereClause(" WHERE ROLE_ID IN( ");
for (size_t i = 0; i < userIDs.size(); i++)
{
if (i > 0)
whereClause += ", ";
whereClause += authIDToString(userIDs[i]);
}
whereClause += ")";
std::string orderByClause(" ORDER BY GRANTEE_ID");
std::vector<MyRow> rows;
MyTable &myTable = static_cast<MyTable &>(myTable_);
if (myTable.selectAllWhere(whereClause,orderByClause,rows) == STATUS_ERROR)
return STATUS_ERROR;
// When we support hierarchical roles, then we need to save all grants to
// roles and recursively check for user grantees.
for (size_t r = 0; r < rows.size(); r++)
{
MyRow &row = rows[r];
if (CmpSeabaseDDLauth::isUserID(row.granteeID_))
granteeIDs.push_back(row.granteeID_);
}
return STATUS_GOOD;
}
//****************** End of PrivMgrRoles::fetchUsersForRole ********************
// *****************************************************************************
// * *
// * Function: PrivMgrRoles::grantRole *
// * *
// * Grants one or more roles to one or more authIDs. *
// * *
// *****************************************************************************
// * *
// * Parameters: *
// * *
// * <roleIDs> const std::vector<int32_t> & In *
// * is a vector of roleIDs. The caller is responsible for ensuring all *
// * IDs are unique. *
// * *
// * <roleNames> const std::vector<std::string> & In *
// * is a list of role names. The elements in <roleIDs> must correspond *
// * to the elements in <roleNames>, i.e., roleIDs[n] is the role ID for *
// * the role with name roleNames[n]. *
// * *
// * <grantorIDs> const std::vector<int32_t> & In *
// * is a vector of authIDs granting the role. The elements of the vector *
// * are for the corresponding role entry. *
// * *
// * <grantorNames> const std::vector<std::string> & In *
// * is a list of names of the authID granting the role in the *
// * corresponding position in the role vectors. *
// * *
// * <grantorClass PrivAuthClass In *
// * is the auth class of the authID granting the role. Currently only *
// * user is supported. *
// * *
// * <granteeIDs> const std::vector<int32_t> & In *
// * is a vector of authIDs being granted the role. The caller is *
// * responsible for ensuring all IDs are unique. *
// * *
// * <granteeNames> const std::vector<std::string> & In *
// * is a list of grantee names. The elements in <grantees> must correspond*
// * to the elements in <granteeNames>, i.e., granteeIDs[n] is the numeric *
// * auth ID for authorization ID with the name granteeNames[n]. *
// * *
// * <granteeClasses> const std::vector<PrivAuthClass> & In *
// * is a list of classes for each grantee. List must correspond to *
// * <grantees>. Currently only user is supported. *
// * *
// * <grantDepth> const int64_t In *
// * is the number of levels this role may be granted by the grantee. *
// * Initially this is either 0 or -1. *
// * *
// *****************************************************************************
// * *
// * Returns: PrivStatus *
// * *
// * STATUS_GOOD: Roles were granted. *
// * *: One or more roles were not granted. *
// * A CLI error is put into the diags area. *
// * *
// *****************************************************************************
PrivStatus PrivMgrRoles::grantRole(
const std::vector<int32_t> & roleIDs,
const std::vector<std::string> & roleNames,
const std::vector<int32_t> & grantorIDs,
const std::vector<std::string> & grantorNames,
PrivAuthClass grantorClass,
const std::vector<int32_t> & granteeIDs,
const std::vector<std::string> & granteeNames,
const std::vector<PrivAuthClass> & granteeClasses,
const int32_t grantDepth)
{
NABoolean doDebug = (getenv("DBUSER_DEBUG") ? TRUE : FALSE);
bool roleWasGranted = false;
MyTable &myTable = static_cast<MyTable &>(myTable_);
int32_t numKeys = roleIDs.size() * granteeIDs.size();
SQL_QIKEY siKeyList[numKeys];
size_t siIndex = 0;
for (size_t r = 0; r < roleIDs.size(); r++)
{
int32_t roleID = roleIDs[r];
// if the roleID is PUBLIC return an error
if (roleID == PUBLIC_USER)
{
*pDiags_ << DgSqlCode (-CAT_IS_NOT_A_ROLE)
<< DgString0(PUBLIC_AUTH_NAME);
return STATUS_ERROR;
}
// For each role ID we loop through the list of grantees.
// Most of the WHERE clause is known for this role (only
// difference is the grantee), so build the header now.
std::string whereClauseHeader(" WHERE ROLE_ID = ");
whereClauseHeader += authIDToString(roleID);
whereClauseHeader += " AND GRANTOR_ID = ";
whereClauseHeader += authIDToString(grantorIDs[r]);
whereClauseHeader += " AND GRANTEE_ID = ";
for (size_t g = 0; g < granteeIDs.size(); g++)
{
// Currently roles cannot be granted to PUBLIC. This restriction
// could be lifted in the future. Grants to _SYSTEM never make sense.
if (granteeIDs[g] == SYSTEM_USER || granteeIDs[g] == PUBLIC_USER)
{
*pDiags_ << DgSqlCode(-CAT_NO_GRANT_ROLE_TO_PUBLIC_OR_SYSTEM);
return STATUS_ERROR;
}
if (granteeIDs[g] == grantorIDs[r] ||
granteeIDs[g] == ComUser::getRootUserID())
{
*pDiags_ << DgSqlCode(-CAT_CANT_GRANT_TO_SELF_OR_ROOT);
return STATUS_ERROR;
}
// Determine if the grant is new (auth ID does not have role),
// an update (authID has role, but not with grant option),
// or is a NOP (authID already has role and with grant is not changing).
bool update = false;
int32_t thisGrantDepth;
if (grantExists(roleID,grantorIDs[r],granteeIDs[g],thisGrantDepth))
{
// If privilege is already granted, just move on to the next entry.
// Note, if adding WITH GRANT OPTION, perform an update.
if (thisGrantDepth == grantDepth || grantDepth == 0)
continue;
update = true;
}
// Does grantor have authority to grant this role?
//TODO: include role name in error message, specific msg for grant role
if (!hasWGO(grantorIDs[r],roleID))
{
*pDiags_ << DgSqlCode(-CAT_NOT_AUTHORIZED);
return STATUS_ERROR;
}
roleWasGranted = true;
PrivStatus privStatus = STATUS_GOOD;
if (update) // Set new grant depth
{
std::string whereClause = whereClauseHeader + authIDToString(granteeIDs[g]);
std::string setClause(" SET GRANT_DEPTH = ");
char grantDepthString[20];
sprintf(grantDepthString,"%d",grantDepth);
setClause += grantDepthString + whereClause;
privStatus = myTable.update(setClause);
}
else // Grant role to grantee from grantor.
{
MyRow row(fullTableName_);
row.roleID_ = roleIDs[r];
row.roleName_ = roleNames[r];
row.granteeID_ = granteeIDs[g];
row.granteeName_ = granteeNames[g];
row.granteeAuthClass_ = granteeClasses[g];
row.grantorID_ = grantorIDs[r];
row.grantorName_ = grantorNames[r];
row.grantorAuthClass_ = grantorClass;
row.grantDepth_ = grantDepth;
privStatus = myTable.insert(row);
}
if (privStatus != STATUS_GOOD)
{
if (pDiags_->getNumber(DgSqlCode::ERROR_) == 0)
PRIVMGR_INTERNAL_ERROR("I/O error granting role");
return STATUS_ERROR;
}
// Add a special secKey to indicate a role grant. This forces the role
// list in cache to be regenerated
ComSecurityKey secKey(granteeIDs[g],roleIDs[r],ComSecurityKey::SUBJECT_IS_GRANT_ROLE);
siKeyList[siIndex].revokeKey.subject = secKey.getSubjectHashValue();
siKeyList[siIndex].revokeKey.object = secKey.getObjectHashValue();
std::string actionString;
secKey.getSecurityKeyTypeAsLit(actionString);
strncpy(siKeyList[siIndex].operation, actionString.c_str(),2);
if (doDebug)
{
NAString msg (secKey.print(granteeIDs[g], roleIDs[r]));
printf("[DBUSER:%d] grant role %s\n",
(int) getpid(), msg.data());
fflush(stdout);
}
siIndex++;
}//grantees
}//roles
// Call the CLI to send details to RMS
SQL_EXEC_SetSecInvalidKeys(siIndex,siKeyList);
//TODO: if we didn't have any errors, but no roles were granted, then all
// grants are already performed. Should issue some message.
// Related, need option to suppress already exists and does not exist errors.
// if (!roleWasGranted)
// {
// //TODO: error or warning
// }
return STATUS_GOOD;
}
//********************** End of PrivMgrRoles::grantRole ************************
// *****************************************************************************
// * *
// * Function: PrivMgrRoles::grantRoleToCreator *
// * *
// * Grants role to creator from _SYSTEM. *
// * *
// *****************************************************************************
// * *
// * Parameters: *
// * *
// * <roleID> const int32_t In *
// * is the ID of the role being created. *
// * *
// * <roleName> const std::string & In *
// * is the name of the role being created. *
// * *
// * <granteeID> const int32_t In *
// * is the ID of the creator of the role. *
// * *
// * <granteeName> const std::string & In *
// * is the name of the creator of the role. *
// * *
// *****************************************************************************
// * *
// * Returns: PrivStatus *
// * *
// * STATUS_GOOD: Role was granted to the user by _SYSTEM. *
// * *: Role was not granted due to I/O error. *
// * A CLI error is put into the diags area. *
// * *
// *****************************************************************************
PrivStatus PrivMgrRoles::grantRoleToCreator(
const int32_t roleID,
const std::string & roleName,
const int32_t granteeID,
const std::string granteeName)
{
MyTable &myTable = static_cast<MyTable &>(myTable_);
MyRow row(fullTableName_);
row.roleID_ = roleID;
row.roleName_ = roleName;
row.granteeID_ = granteeID;
row.granteeName_ = granteeName;
row.granteeAuthClass_ = PrivAuthClass::USER;
row.grantorID_ = SYSTEM_USER;
row.grantorName_ = SYSTEM_AUTH_NAME;
row.grantorAuthClass_ = PrivAuthClass::USER;
row.grantDepth_ = -1;
return myTable.insert(row);
}
//***************** End of PrivMgrRoles::grantRoleToCreator ********************
// *****************************************************************************
// * *
// * Function: PrivMgrRoles::hasRole *
// * *
// * Determines if an authID has been granted a role. *
// * *
// *****************************************************************************
// * *
// * Parameters: *
// * *
// * <authID> const int32_t In *
// * is the authorization ID. *
// * *
// * <roleID> const int32_t In *
// * is the role ID. *
// * *
// *****************************************************************************
// * *
// * Returns: bool *
// * *
// * true: Role has been granted to this authorization ID. *
// * false: Role has not been granted to this authorization ID, or there was *
// * an error trying to read from the ROLE_USAGE table. *
// * *
// *****************************************************************************
bool PrivMgrRoles::hasRole(
int32_t authID,
int32_t roleID)
{
MyTable &myTable = static_cast<MyTable &>(myTable_);
std::string whereClause ("WHERE ROLE_ID = ");
whereClause += authIDToString(roleID);
whereClause += " AND GRANTEE_ID = ";
whereClause += authIDToString(authID);
// set pointer in diags area
int32_t diagsMark = pDiags_->mark();
int64_t rowCount = 0;
PrivStatus privStatus = myTable.selectCountWhere(whereClause,rowCount);
if ((privStatus == STATUS_GOOD || privStatus == STATUS_WARNING) &&
rowCount > 0)
return true;
pDiags_->rewind(diagsMark);
return false;
}
//*********************** End of PrivMgrRoles::hasRole *************************
// *****************************************************************************
// * *
// * Function: PrivMgrRoles::hasWGO *
// * *
// * Determines if an authID has been granted a role with admin (aka with *
// * grant option). *
// * *
// *****************************************************************************
// * *
// * Parameters: *
// * *
// * <authID> const int32_t In *
// * is the authorization ID. *
// * *
// * <roleID> const int32_t In *
// * is the role ID. *
// * *
// *****************************************************************************
// * *
// * Returns: bool *
// * *
// * true: Role has been granted to this authorization ID with admin. *
// * false: Role has not been granted with admin to this authorization ID, *
// * or there was an error trying to read from the ROLE_USAGE table. *
// * *
// *****************************************************************************
bool PrivMgrRoles::hasWGO(
int32_t authID,
int32_t roleID)
{
MyTable &myTable = static_cast<MyTable &>(myTable_);
std::string whereClause (" WHERE ROLE_ID = ");
whereClause += authIDToString(roleID);
whereClause += " AND GRANTEE_ID = ";
whereClause += authIDToString(authID);
whereClause += " AND GRANT_DEPTH <> 0";
// set pointer in diags area
int32_t diagsMark = pDiags_->mark();
int64_t rowCount = 0;
PrivStatus privStatus = myTable.selectCountWhere(whereClause,rowCount);
if ((privStatus == STATUS_GOOD || privStatus == STATUS_WARNING) &&
rowCount > 0)
return true;
pDiags_->rewind(diagsMark);
return false;
}
//************************ End of PrivMgrRoles::hasWGO *************************
// *****************************************************************************
// * *
// * Function: PrivMgrRoles::grantExists *
// * *
// * Determines if a specific authorization ID (granteee) has been granted *
// * a role by a specific authorization ID (grantor). *
// * *
// *****************************************************************************
// * *
// * Parameters: *
// * *
// * <roleID> const int32_t In *
// * is the role ID. *
// * *
// * <grantorID> const int32_t In *
// * is the authorization ID of the grantor. *
// * *
// * <granteeID> const int32_t In *
// * is the authorization ID of the grantee. *
// * *
// * <grantDepth> int32_t & In *
// * passes back the grant depth if the role grant exists. *
// * *
// *****************************************************************************
// * *
// * Returns: bool *
// * *
// * true: Role has been granted to grantee by grantor. *
// * false: Role has not been granted to grantee by grantor, or there was an *
// * error trying to read from the ROLE_USAGE table. *
// * *
// *****************************************************************************
bool PrivMgrRoles::grantExists(
const int32_t roleID,
const int32_t grantorID,
const int32_t granteeID,
int32_t & grantDepth)
{
MyTable &myTable = static_cast<MyTable &>(myTable_);
std::string whereClause ("WHERE ROLE_ID = ");
whereClause += authIDToString(roleID);
whereClause += " AND GRANTOR_ID = ";
whereClause += authIDToString(grantorID);
whereClause += " AND GRANTEE_ID = ";
whereClause += authIDToString(granteeID);
// set pointer in diags area
int32_t diagsMark = pDiags_->mark();
MyRow row(fullTableName_);
PrivStatus privStatus = myTable.selectWhereUnique(whereClause,row);
if (privStatus == STATUS_GOOD || privStatus == STATUS_WARNING)
{
grantDepth = row.grantDepth_;
return true;
}
pDiags_->rewind(diagsMark);
return false;
}
//********************** End of PrivMgrRoles::grantExists **********************
// *****************************************************************************
// * *
// * Function: PrivMgrRoles::isGranted *
// * *
// * Determines if a role has been granted, i.e., if it is used in the *
// * ROLE_USAGE table. *
// * *
// *****************************************************************************
// * *
// * Parameters: *
// * *
// * <roleID> const int32_t In *
// * is the role ID. *
// * *
// * <shouldExcludeGrantsBySystem> const bool [In] *
// * if true, don't consider the system grant to the creator. *
// * *
// *****************************************************************************
// * *
// * Returns: bool *
// * *
// * true: Role has been granted to one or more authIDs. *
// * false: Role has not been granted, or there was an error trying to *
// * read from the ROLE_USAGE table. *
// * *
// *****************************************************************************
bool PrivMgrRoles::isGranted(
const int32_t roleID,
const bool shouldExcludeGrantsBySystem)
{
MyRow row(fullTableName_);
MyTable &myTable = static_cast<MyTable &>(myTable_);
std::string whereClause("WHERE ROLE_ID = ");
whereClause += authIDToString(roleID);
if (shouldExcludeGrantsBySystem)
whereClause += " AND GRANTOR_ID <> -2";
// set pointer in diags area
int32_t diagsMark = pDiags_->mark();
int64_t rowCount = 0;
PrivStatus privStatus = myTable.selectCountWhere(whereClause,rowCount);
if ((privStatus == STATUS_GOOD || privStatus == STATUS_WARNING) &&
rowCount > 0)
return true;
pDiags_->rewind(diagsMark);
return false;
}
//*********************** End of PrivMgrRoles::isGranted ***********************
// *****************************************************************************
// * *
// * Function: PrivMgrRoles::isUserGrantedAnyRole *
// * *
// * Determines if an authorization ID has been granted any role. *
// * *
// *****************************************************************************
// * *
// * Parameters: *
// * *
// * <authID> const int32_t In *
// * is the authorization ID. *
// * *
// *****************************************************************************
// * *
// * Returns: bool *
// * *
// * true: Authorization ID has been granted one or more roles. *
// * false: Authorization ID has not been granted any roles, or there was *
// * an error trying to read from the ROLE_USAGE table. *
// * *
// *****************************************************************************
bool PrivMgrRoles::isUserGrantedAnyRole(const int32_t authID)
{
MyRow row(fullTableName_);
MyTable &myTable = static_cast<MyTable &>(myTable_);
std::string whereClause(" WHERE GRANTEE_ID = ");
whereClause += authIDToString(authID);
// set pointer in diags area
int32_t diagsMark = pDiags_->mark();
int64_t rowCount = 0;
PrivStatus privStatus = myTable.selectCountWhere(whereClause,rowCount);
if ((privStatus == STATUS_GOOD || privStatus == STATUS_WARNING) &&
rowCount > 0)
return true;
pDiags_->rewind(diagsMark);
return false;
}
//***************** End of PrivMgrRoles::isUserGrantedAnyRole ******************
// *****************************************************************************
// * Function: PrivMgrRoles::populateCreatorGrants *
// * *
// * Inserts rows into the ROLE_USAGE table during authorization *
// * initialization for existing roles. *
// * *
// *****************************************************************************
// * *
// * Parameters: *
// * *
// * <authsLocation> const std::string & In *
// * is the location of the AUTHS table containing the Trafodion users *
// * and roles. *
// * *
// *****************************************************************************
// * *
// * Returns: PrivStatus *
// * *
// * STATUS_GOOD: ROLE_USAGE table was populated with owner grants. *
// * *: ROLE_USAGE was not populated. A CLI error is put into *
// * the diags area. *
// * *
// *****************************************************************************
PrivStatus PrivMgrRoles::populateCreatorGrants(
const std::string & authsLocation,
const std::vector<std::string> &rolesToAdd)
{
std::string traceMsg;
PrivMgr::log (__FILE__, "populating ROLE_USAGE table", -1);
MyTable &myTable = static_cast<MyTable &>(myTable_);
int32_t numberRoles = sizeof(systemRoles)/sizeof(SystemAuthsStruct) -
NUMBER_SPECIAL_SYSTEM_ROLES;
// Calculate the number of roles that have already been created
int64_t expectedRows = numberRoles - rolesToAdd.size();
std::string whereClause;
int64_t foundRows = 0;
PrivStatus privStatus = myTable.selectCountWhere(whereClause,foundRows);
if (privStatus == STATUS_ERROR)
return privStatus;
if (foundRows != expectedRows)
{
std::string message ("Found ");
message += to_string((long long int)foundRows);
message += " rows in ROLE_USAGE table, expecting ";
message += to_string((long long int)expectedRows);
message += " rows";
traceMsg = "ERROR: ";
traceMsg += message;
PrivMgr::log(__FILE__, message, -1);
PRIVMGR_INTERNAL_ERROR(message.c_str());
return STATUS_ERROR;
}
// insert the rows
std::string inClause (" auth_db_name in (");
std::string sep = "";
for (size_t i = 0; i < rolesToAdd.size(); i++)
{
inClause.append(sep);
inClause.append ("'");
inClause.append(rolesToAdd[i]);
inClause.append ("'");
sep = ",";
}
inClause += ")";
privStatus = myTable.insertSelect(authsLocation, inClause);
if (privStatus == STATUS_ERROR)
{
traceMsg = "ERROR unable to populate ROLE_USAGE: ";
traceMsg += to_string((long long int)pDiags_->mainSQLCODE());
PrivMgr::log (__FILE__, traceMsg, -1);
return privStatus;
}
// make sure that the number rows inserted match the total.
// get the number of rows inserted
int64_t insertedRows;
privStatus = myTable.selectCountWhere(whereClause,insertedRows);
if (privStatus == STATUS_ERROR)
return privStatus;
// get number rows expected
std::string selectStmt ("SELECT COUNT(*) FROM ");
int32_t actualSize = 0;
char buf[500];
if (ComUser::getRoleList(buf, actualSize, 500))
{
PRIVMGR_INTERNAL_ERROR("internal error getting role list");
return STATUS_ERROR;
}
whereClause = " where AUTH_TYPE = 'R' AND AUTH_DB_NAME IN (";
whereClause += buf;
whereClause += ")";
selectStmt += authsLocation;
selectStmt += " ";
selectStmt += whereClause;
int32_t length = 0;
ExeCliInterface cliInterface(STMTHEAP);
int32_t cliRC = cliInterface.executeImmediate(selectStmt.c_str(),
(char*)&expectedRows,
&length,FALSE);
if (cliRC < 0)
{
cliInterface.retrieveSQLDiagnostics(CmpCommon::diags());
return STATUS_ERROR;
}
// Check to see if rows inserted match expected rows
if (numberRoles != insertedRows)
{
std::string message ("Expected to find ");
message += to_string((long long int)expectedRows);
message += " rows into ROLE_USAGE table, instead ";
message += to_string((long long int)insertedRows);
message += " were found.";
traceMsg = "ERROR: ";
traceMsg += message;
PrivMgr::log(__FILE__, traceMsg, -1);
PRIVMGR_INTERNAL_ERROR(message.c_str());
return STATUS_ERROR;
}
return STATUS_GOOD;
}
//***************** End of PrivMgrRoles::populateCreatorGrants *****************
// *****************************************************************************
// * Function: PrivMgrRoles::revokeAllForGrantor *
// * *
// * Revokes grants from a specified grantor. *
// * *
// *****************************************************************************
// * *
// * Parameters: *
// * *
// * <grantorID> const int32_t In *
// * is the unique ID of the authID whose grants are to be revoked. *
// * *
// * <roleID> const int32_t In *
// * is the ID of the role to be revoked. *
// * *
// * <isGOFSpecified> const bool In *
// * is true if admin rights are being revoked. *
// * *
// * <newGrantDepth> const int32_t In *
// * is the number of levels this privilege may be granted by the grantee. *
// * Initially this is always 0 when revoking. *
// * *
// * <dropBehavior> PrivDropBehavior In *
// * indicates whether restrict or cascade behavior is requested. *
// * *
// *****************************************************************************
// * *
// * Returns: PrivStatus *
// * *
// * STATUS_GOOD: All grants of the role by this grantor were revoked (or *
// * there were none). *
// * *: Could not revoke grants. A CLI error is put into *
// * the diags area. *
// * *
// *****************************************************************************
PrivStatus PrivMgrRoles::revokeAllForGrantor(
const int32_t grantorID,
const int32_t roleID,
const bool isGOFSpecified,
const int32_t newGrantDepth,
PrivDropBehavior dropBehavior)
{
// *****************************************************************************
// * *
// * First, get all the rows where the grantor has granted this role to any *
// * authorization ID. *
// * *
// *****************************************************************************
std::string whereClause("WHERE ROLE_ID = ");
whereClause += authIDToString(roleID);
whereClause += " AND GRANTOR_ID = ";
whereClause += authIDToString(grantorID);
std::string orderByClause;
std::vector<MyRow> rows;
MyTable &myTable = static_cast<MyTable &>(myTable_);
PrivStatus privStatus = myTable.selectAllWhere(whereClause,orderByClause,rows);
// *****************************************************************************
// * *
// * If the grantor has no active grants for this role, we are done. *
// * *
// *****************************************************************************
if (privStatus == STATUS_NOTFOUND)
return STATUS_GOOD;
// *****************************************************************************
// * *
// * Unexpected problem, let the caller deal with it. *
// * *
// *****************************************************************************
if (privStatus != STATUS_GOOD && privStatus != STATUS_WARNING)
return privStatus;
// *****************************************************************************
// * *
// * If there are grants and drop behavior is RESTRICT, return an error. *
// * *
// *****************************************************************************
if (dropBehavior == PrivDropBehavior::RESTRICT)
{
*pDiags_ << DgSqlCode(-CAT_ROLE_IS_GRANTED_NO_REVOKE)
<< DgString0(rows[0].roleName_.c_str())
<< DgString1(rows[0].grantorName_.c_str());
return STATUS_ERROR;
}
// *****************************************************************************
// * *
// * There are one more grants from the grantor of this role. Build the *
// * lists of grantees and auth types, plus a one element role ID list, and *
// * call revokeRole (our likely caller). *
// * *
// *****************************************************************************
std::vector<int32_t> granteeIDs;
std::vector<PrivAuthClass> granteeClasses;
std::vector<int32_t> grantorIDs;
for (size_t r = 0; r < rows.size(); r++)
{
MyRow &row = rows[r];
granteeIDs.push_back(row.granteeID_);
granteeClasses.push_back(row.granteeAuthClass_);
grantorIDs.push_back(grantorID);
}
std::vector<int32_t> roleIDs;
roleIDs.push_back(roleID);
return revokeRole(roleIDs,granteeIDs,granteeClasses,grantorIDs,
isGOFSpecified,newGrantDepth,dropBehavior);
}
//****************** End of PrivMgrRoles::revokeAllForGrantor ******************
// *****************************************************************************
// * *
// * Function: PrivMgrRoles::revokeRole *
// * *
// * This function revokes one or more roles from one or more *
// * authorization IDs. *
// * *
// *****************************************************************************
// * *
// * Parameters: *
// * *
// * <roleIDs> const std::vector<int32_t> & In *
// * is a vector of roleIDs. The caller is responsible for ensuring all *
// * IDs are unique. *
// * *
// * <granteeIDs> const std::vector<int32_t> & In *
// * is a vector of granteeIDs. The caller is responsible for ensuring all *
// * IDs are unique. *
// * *
// * <granteeClasses> const std::vector<PrivAuthClass> & In *
// * is a vector of PrivAuthClass corresponding the granteeID in the same *
// * position in the granteeIDs vector. *
// * *
// * <grantorIDs> const std::vector<int32_t> & In *
// * is a vector of authIDs that granted the role. The elements of the *
// * vector are for the corresponding role entry. *
// * *
// * <isGOFSpecified> const bool In *
// * is true if admin rights are being revoked. *
// * *
// * <newGrantDepth> const int32_t In *
// * is the number of levels this privilege may be granted by the grantee. *
// * Initially this is always 0 when revoking. *
// * *
// * <dropBehavior> PrivDropBehavior In *
// * indicates whether restrict or cascade behavior is requested. *
// * *
// *****************************************************************************
// * *
// * Returns: PrivStatus *
// * *
// * STATUS_GOOD: Role(s) were revoked *
// * *: One or more roles were not revoked. *
// * A CLI error is put into the diags area. *
// * *
// *****************************************************************************
PrivStatus PrivMgrRoles::revokeRole(
const std::vector<int32_t> & roleIDs,
const std::vector<int32_t> & granteeIDs,
const std::vector<PrivAuthClass> & granteeClasses,
const std::vector<int32_t> & grantorIDs,
const bool isGOFSpecified,
const int32_t newGrantDepth,
PrivDropBehavior dropBehavior)
{
//TODO: Currently only RESTRICT behavior is supported.
NABoolean doDebug = (getenv("DBUSER_DEBUG") ? TRUE : FALSE);
if (dropBehavior == PrivDropBehavior::CASCADE)
{
*pDiags_ << DgSqlCode(-21001) << DgString0("CASCADE");
return STATUS_ERROR;
}
PrivStatus privStatus = STATUS_GOOD;
for (size_t r = 0; r < roleIDs.size(); r++)
{
int32_t roleID = roleIDs[r];
for (size_t g = 0; g < granteeIDs.size(); g++)
{
int32_t grantDepth;
if (!grantExists(roleID,grantorIDs[r],granteeIDs[g],grantDepth))
{
int32_t length;
char roleName[MAX_DBUSERNAME_LEN + 1];
Int16 retCode = ComUser::getAuthNameFromAuthID(roleID,roleName,
sizeof(roleName),
length);
// Should not fail, role ID was derived from name provided by user.
if (retCode != 0)
{
std::string errorText("Unable to look up role name for role ID ");
errorText += authIDToString(roleID);
PRIVMGR_INTERNAL_ERROR(errorText.c_str());
return STATUS_ERROR;
}
char grantorName[MAX_DBUSERNAME_LEN + 1];
retCode = ComUser::getAuthNameFromAuthID(grantorIDs[r],
grantorName,
sizeof(grantorName),
length);
// Should not fail, grantor ID was derived from name provided by user.
if (retCode != 0)
{
std::string errorText("Unable to look up grantor name for ID ");
errorText += authIDToString(grantorIDs[r]);
PRIVMGR_INTERNAL_ERROR(errorText.c_str());
return STATUS_ERROR;
}
char granteeName[MAX_DBUSERNAME_LEN + 1];
retCode = ComUser::getAuthNameFromAuthID(granteeIDs[g],
granteeName,
sizeof(granteeName),
length);
// Should not fail, grantee ID was derived from name provided by user.
if (retCode != 0)
{
std::string errorText("Unable to look up grantee name for ID ");
errorText += authIDToString(granteeIDs[g]);
PRIVMGR_INTERNAL_ERROR(errorText.c_str());
return STATUS_ERROR;
}
*pDiags_ << DgSqlCode(-CAT_GRANT_NOT_FOUND)
<< DgString0(roleName)
<< DgString1(grantorName)
<< DgString2(granteeName);
continue;
}
if (hasWGO(granteeIDs[g],roleID))
{
privStatus = revokeAllForGrantor(granteeIDs[g],roleID,
isGOFSpecified,newGrantDepth,
dropBehavior);
if (privStatus != STATUS_GOOD)
return STATUS_ERROR;
}
if (dependentObjectsExist(granteeIDs[g],roleID,dropBehavior))
return STATUS_ERROR;
}
}
// All checks completed, all dependent grants revoked, and when CASCADE is
// supported, all dependent objects dropped. It's now safe to revoke the roles.
std::string setClause("SET GRANT_DEPTH = ");
if (isGOFSpecified)
{
char grantDepthString[20];
sprintf(grantDepthString,"%d",newGrantDepth);
setClause += grantDepthString;
}
int32_t numKeys = roleIDs.size() * granteeIDs.size();
SQL_QIKEY siKeyList[numKeys];
size_t siIndex = 0;
for (size_t r2 = 0; r2 < roleIDs.size(); r2++)
{
std::string whereClauseHeader(" WHERE ROLE_ID = ");
whereClauseHeader += authIDToString(roleIDs[r2]);
whereClauseHeader += " AND GRANTOR_ID = ";
whereClauseHeader += authIDToString(grantorIDs[r2]);
for (size_t g2 = 0; g2 < granteeIDs.size(); g2++)
{
std::string whereClause(whereClauseHeader);
whereClause += " AND GRANTEE_ID = ";
whereClause += authIDToString(granteeIDs[g2]);
MyTable &myTable = static_cast<MyTable &>(myTable_);
if (isGOFSpecified)
{
std::string updateClause = setClause + whereClause;
privStatus = myTable.update(updateClause);
}
else
privStatus = myTable.deleteWhere(whereClause);
if (privStatus != STATUS_GOOD)
{
if (pDiags_->getNumber(DgSqlCode::ERROR_) == 0)
PRIVMGR_INTERNAL_ERROR("I/O error revoking role");
return STATUS_ERROR;
}
ComSecurityKey secKey(granteeIDs[g2],roleIDs[r2],
ComSecurityKey::SUBJECT_IS_USER);
siKeyList[siIndex].revokeKey.subject = secKey.getSubjectHashValue();
siKeyList[siIndex].revokeKey.object = secKey.getObjectHashValue();
std::string actionString;
secKey.getSecurityKeyTypeAsLit(actionString);
strncpy(siKeyList[siIndex].operation, actionString.c_str(),2);
if (doDebug)
{
NAString msg (secKey.print(granteeIDs[g2], roleIDs[r2]));
printf("[DBUSER:%d] revoke role %s\n",
(int) getpid(), msg.data());
fflush(stdout);
}
siIndex++;
}
}
// Call the CLI to send details to RMS
SQL_EXEC_SetSecInvalidKeys(siIndex,siKeyList);
return STATUS_GOOD;
}
//********************** End of PrivMgrRoles::revokeRole ***********************
// *****************************************************************************
// * *
// * Function: PrivMgrRoles::revokeRoleFromCreator *
// * *
// * Revokes the system granted role to the creator of the role. *
// * *
// *****************************************************************************
// * *
// * Parameters: *
// * *
// * <roleID> const int32_t In *
// * is the role ID. *
// * *
// * <granteeID> const int32_t In *
// * is the ID of the authorization ID that created the role. *
// * *
// *****************************************************************************
// * *
// * Returns: PrivStatus *
// * *
// * STATUS_GOOD: Role was revoked. *
// * *: Role was not revoked. A CLI error is put into the diags area *
// * *
// *****************************************************************************
PrivStatus PrivMgrRoles::revokeRoleFromCreator(
const int32_t roleID,
const int32_t granteeID)
{
MyTable &myTable = static_cast<MyTable &>(myTable_);
std::string whereClause(" WHERE ROLE_ID = ");
whereClause += authIDToString(roleID);
whereClause += " AND GRANTEE_ID = ";
whereClause += authIDToString(granteeID);
whereClause += " AND GRANTOR_ID = -2";
return myTable.deleteWhere(whereClause);
}
//**************** End of PrivMgrRoles::revokeRoleFromCreator ******************
// *****************************************************************************
// MyTable methods
// *****************************************************************************
// *****************************************************************************
// * *
// * Function: MyTable::insert *
// * *
// * Inserts a row into the ROLE_USAGE table. *
// * *
// *****************************************************************************
// * *
// * Parameters: *
// * *
// * <rowIn> const PrivMgrMDRow & In *
// * is a MyRow to be inserted. *
// * *
// *****************************************************************************
// * *
// * Returns: PrivStatus *
// * *
// * STATUS_GOOD: Row inserted. *
// * *: Insert failed. A CLI error is put into the diags area. *
// * *
// *****************************************************************************
PrivStatus MyTable::insert(const PrivMgrMDRow & rowIn)
{
const MyRow & row = static_cast<const MyRow &>(rowIn);
char insertStatement[1000];
char granteeAuthClass[3] = {0};
switch (row.granteeAuthClass_)
{
case PrivAuthClass::USER:
granteeAuthClass[0] = 'U';
break;
case PrivAuthClass::ROLE:
granteeAuthClass[0] = 'R';
break;
default:
granteeAuthClass[0] = ' ';
}
char grantorAuthClass[3] = {0};
switch (row.grantorAuthClass_)
{
case PrivAuthClass::USER:
grantorAuthClass[0] = 'U';
break;
case PrivAuthClass::ROLE:
grantorAuthClass[0] = 'R';
break;
default:
grantorAuthClass[0] = ' ';
}
sprintf(insertStatement,"insert into %s values (%d, '%s', %d, '%s', '%s', %d, '%s', '%s', %d)",
tableName_.c_str(),
row.roleID_,
row.roleName_.c_str(),
row.granteeID_,
row.granteeName_.c_str(),
granteeAuthClass,
row.grantorID_,
row.grantorName_.c_str(),
grantorAuthClass,
row.grantDepth_);
return CLIImmediate(insertStatement);
}
//************************** End of MyTable::insert ****************************
// *****************************************************************************
// * *
// * Function: MyTable::insertSelect *
// * *
// * Inserts a row into the ROLE_USAGE table granting a role to its *
// * owner for every role defined in the AUTHS table. *
// * *
// *****************************************************************************
// * *
// * Parameters: *
// * *
// * <authsLocation> const std::string & In *
// * is the fully qualified AUTHS table name. *
// * *
// *****************************************************************************
// * *
// * Returns: PrivStatus *
// * *
// * STATUS_GOOD: Row inserted. *
// * *: Insert failed. A CLI error is put into the diags area. *
// * *
// *****************************************************************************
PrivStatus MyTable::insertSelect(
const std::string & authsLocation,
const std::string & inClause)
{
char insertStatement[2000];
sprintf(insertStatement, "INSERT INTO %s SELECT A1.AUTH_ID, A1.AUTH_DB_NAME, A1.AUTH_CREATOR,"
"(SELECT AUTH_DB_NAME FROM %s A2 WHERE A2.auth_ID = A1.AUTH_CREATOR),"
"(SELECT AUTH_TYPE FROM %s A3 WHERE A3.auth_ID = A1.AUTH_CREATOR),"
"-2,'_SYSTEM','%c',-1 FROM %s A1 WHERE A1.AUTH_TYPE = 'R' AND %s",
tableName_.c_str(),authsLocation.c_str(),authsLocation.c_str(),
'U',authsLocation.c_str(), inClause.c_str());
return CLIImmediate(insertStatement);
}
//*********************** End of MyTable::insertSelect *************************
// *****************************************************************************
// * *
// * Function: MyTable::selectAllWhere *
// * *
// * Selects rows from the ROLE_USAGE table based on the specified *
// * WHERE clause and sorted per an optional ORDER BY clause. *
// * *
// *****************************************************************************
// * *
// * Parameters: *
// * *
// * <whereClause> const std::string & In *
// * is the WHERE clause specifying a unique row. *
// * *
// * <orderByClause> const std::string & In *
// * is an optional ORDER BY clause. *
// * *
// * <rowOut> PrivMgrMDRow & Out *
// * passes back a MyRow. *
// * *
// *****************************************************************************
// * *
// * Returns: PrivStatus *
// * *
// * STATUS_GOOD: Row returned. *
// * *: Select failed. A CLI error is put into the diags area. *
// * *
// *****************************************************************************
PrivStatus MyTable::selectAllWhere(
const std::string & whereClause,
const std::string & orderByClause,
std::vector<MyRow> & rows)
{
std::string selectStmt ("SELECT ROLE_ID, ROLE_NAME, GRANTEE_ID, GRANTEE_NAME, "
"GRANTEE_AUTH_CLASS, GRANTOR_ID, GRANTOR_NAME, "
"GRANTOR_AUTH_CLASS, GRANT_DEPTH FROM ");
selectStmt += tableName_;
selectStmt += " ";
selectStmt += whereClause;
selectStmt += " ";
selectStmt += orderByClause;
Queue * tableQueue = NULL;
PrivStatus privStatus = executeFetchAll(selectStmt,tableQueue);
if (privStatus != STATUS_GOOD)
return privStatus;
if (tableQueue == NULL)
return STATUS_ERROR;
tableQueue->position();
for (int r = 0; r < tableQueue->numEntries(); r++)
{
OutputInfo * pCliRow = (OutputInfo*)tableQueue->getNext();
MyRow row(tableName_);
setRow(*pCliRow,row);
rows.push_back(row);
}
return STATUS_GOOD;
}
//********************** End of MyTable::selectAllWhere ************************
// *****************************************************************************
// * *
// * Function: MyTable::selectWhereUnique *
// * *
// * Selects a row from the ROLE_USAGE table based on the specified *
// * WHERE clause. *
// * *
// *****************************************************************************
// * *
// * Parameters: *
// * *
// * <whereClause> const std::string & In *
// * is the WHERE clause specifying a unique row. *
// * *
// * <rowOut> PrivMgrMDRow & Out *
// * passes back a MyRow. *
// * *
// *****************************************************************************
// * *
// * Returns: PrivStatus *
// * *
// * STATUS_GOOD: Row returned. *
// * *: Select failed. A CLI error is put into the diags area. *
// * *
// *****************************************************************************
PrivStatus MyTable::selectWhereUnique(
const std::string & whereClause,
PrivMgrMDRow & rowOut)
{
// Generate the select statement
std::string selectStmt ("SELECT ROLE_ID, ROLE_NAME, GRANTEE_ID, GRANTEE_NAME, "
"GRANTEE_AUTH_CLASS, GRANTOR_ID, GRANTOR_NAME, "
"GRANTOR_AUTH_CLASS, GRANT_DEPTH FROM ");
selectStmt += tableName_;
selectStmt += " ";
selectStmt += whereClause;
Queue * tableQueue = NULL;
PrivStatus privStatus = executeFetchAll(selectStmt,tableQueue);
if (privStatus != STATUS_GOOD)
return privStatus;
if (tableQueue->numEntries() != 1)
return STATUS_ERROR;
OutputInfo * pCliRow = (OutputInfo*)tableQueue->getNext();
setRow(*pCliRow,rowOut);
return STATUS_GOOD;
}
//********************* End of MyTable::selectWhereUnique **********************
// *****************************************************************************
// * *
// * Function: MyTable::setRow *
// * *
// * Sets the fields of a row. *
// * *
// *****************************************************************************
// * *
// * Parameters: *
// * *
// * <cliInterface> OutputInfo & In *
// * is a reference to CLI interface to the row data that was read. *
// * *
// * <rowOut> PrivMgrMDRow & Out *
// * passes back a MyRow. *
// * *
// *****************************************************************************
void MyTable::setRow(
OutputInfo & cliInterface,
PrivMgrMDRow & rowOut)
{
MyRow & row = static_cast<MyRow &>(rowOut);
char * ptr = NULL;
int32_t length = 0;
char value[500];
// column 1: role_id
cliInterface.get(0,ptr,length);
row.roleID_ = *(reinterpret_cast<int32_t*>(ptr));
// column 2: role_name
cliInterface.get(1,ptr,length);
strncpy(value,ptr,length);
value[length] = 0;
row.roleName_ = value;
// column 3: grantee_ID
cliInterface.get(2,ptr,length);
row.granteeID_ = *(reinterpret_cast<int32_t*>(ptr));
// column 4: grantee_name
cliInterface.get(3,ptr,length);
strncpy(value,ptr,length);
value[length] = 0;
row.granteeName_ = value;
// column 5: grantee_auth_class
cliInterface.get(4,ptr,length);
strncpy(value,ptr,length);
value[length] = 0;
switch (value[0])
{
case 'U':
row.granteeAuthClass_ = PrivAuthClass::USER;
break;
case 'R':
row.granteeAuthClass_ = PrivAuthClass::ROLE;
break;
default:
row.granteeAuthClass_ = PrivAuthClass::UNKNOWN;
}
// column 6: grantor_ID
cliInterface.get(5,ptr,length);
row.grantorID_ = *(reinterpret_cast<int32_t*>(ptr));
// column 7: grantor_name
cliInterface.get(6,ptr,length);
strncpy(value,ptr,length);
value[length] = 0;
row.grantorName_ = value;
// column 8: grantor_auth_class
cliInterface.get(7,ptr,length);
strncpy(value,ptr,length);
value[length] = 0;
switch (value[0])
{
case 'U':
row.grantorAuthClass_ = PrivAuthClass::USER;
break;
case 'R':
row.grantorAuthClass_ = PrivAuthClass::USER;
break;
default:
row.grantorAuthClass_ = PrivAuthClass::UNKNOWN;
}
// column 9: grant_depth
cliInterface.get(8,ptr,length);
row.grantDepth_ = *(reinterpret_cast<int32_t*>(ptr));
lastRowRead_ = row;
}
//************************** End of MyTable::setRow ****************************
// *****************************************************************************
// * *
// * Function: hasValue *
// * *
// * This function determines if a vector contains a value. *
// * *
// *****************************************************************************
// * *
// * Parameters: *
// * *
// * <container> std::vector<int32_t> In *
// * is the vector of 32-bit values. *
// * *
// * <value> int32_t In *
// * is the value to be compared against existing values in the vector. *
// * *
// *****************************************************************************
static bool hasValue(
std::vector<int32_t> container,
int32_t value)
{
for (size_t index = 0; index < container.size(); index++)
if (container[index] == value)
return true;
return false;
}
//***************************** End of hasValue ********************************
// *****************************************************************************
// * *
// * Function: isDependentObjectPrivPair *
// * *
// * This function determines if a privilege bitmap contains the necessary *
// * privilege based on the dependent object type. *
// * *
// *****************************************************************************
// * *
// * Parameters: *
// * *
// * <objectType> ComObjectType In *
// * is the type of object. *
// * *
// * <objectPrivs> PrivMgrBitmap In *
// * is the bitmap of privileges. *
// * *
// *****************************************************************************
static bool isDependentObjectPrivPair(
ComObjectType objectType,
PrivMgrBitmap objectPrivs)
{
switch (objectType)
{
case COM_VIEW_OBJECT:
return objectPrivs.test(SELECT_PRIV);
case COM_USER_DEFINED_ROUTINE_OBJECT:
case COM_STORED_PROCEDURE_OBJECT:
return objectPrivs.test(USAGE_PRIV);
case COM_REFERENTIAL_CONSTRAINT_OBJECT:
return objectPrivs.test(REFERENCES_PRIV);
default:
return false;
}
return false;
}
//********************* End of isDependentObjectPrivPair ***********************