File authenticate_access_class.cpp¶
File List > cubrid > src > object > authenticate_access_class.cpp
Go to the documentation of this file
/*
*
* Copyright 2016 CUBRID Corporation
*
* Licensed 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.
*
*/
/*
* authenticate_access_class.cpp -
*/
#include "authenticate.h"
#include "authenticate_cache.hpp"
#include "authenticate_grant.hpp"
#include "boot_cl.h"
#include "dbi.h"
#include "execute_schema.h" /* do_recreate_filter_index_constr () */
#include "locator_cl.h"
#include "schema_manager.h"
#include "transform.h"
#include "transaction_cl.h"
#include "virtual_object.h"
#include "schema_system_catalog.hpp" /* sm_is_system_class () */
#define UNIQUE_SAVEPOINT_CHANGE_OWNER_WITH_RENAME "cHANGEoWNERwITHrENAME"
#define IS_CATALOG_CLASS(name) sm_is_system_class (std::string_view (name))
enum fetch_by
{
DONT_KNOW, /* Don't know the mop is a class os an instance */
BY_INSTANCE_MOP, /* fetch a class by an instance mop */
BY_CLASS_MOP /* fetch a class by the class mop */
};
typedef enum fetch_by FETCH_BY;
static int fetch_class (MOP op, MOP *return_mop, SM_CLASS **return_class, AU_FETCHMODE fetchmode, FETCH_BY fetch_by);
static int fetch_instance (MOP op, MOBJ *obj_ptr, AU_FETCHMODE fetchmode,
LC_FETCH_VERSION_TYPE read_fetch_version_type);
static int au_fetch_class_internal (MOP op, SM_CLASS **class_ptr, AU_FETCHMODE fetchmode, DB_AUTH type,
FETCH_BY fetch_by);
static int check_authorization (MOP classobj, SM_CLASS *sm_class, DB_AUTH type);
static int is_protected_class (MOP classmop, SM_CLASS *sm_class, DB_AUTH auth);
/*
* au_change_class_owner_including_partitions - This changes the owning user of a class.
* This should be called only by the DBA.
* return: error code
* classmop(in): class whose owner is to change
* owner(in): new owner
*/
int
au_change_class_owner_including_partitions (MOP class_mop, MOP owner_mop)
{
SM_CLASS *class_ = NULL;
SM_ATTRIBUTE *attr = NULL;
SM_CLASS_CONSTRAINT *constraints = NULL;
SM_CONSTRAINT_INFO *save_constraints = NULL;
SM_CONSTRAINT_INFO *saved = NULL;
MOBJ obj = NULL;
char *class_old_name = NULL;
char *class_new_name = NULL;
char *owner_name = NULL;
char downcase_owner_name[DB_MAX_USER_LENGTH] = { '\0' };
char buf[DB_MAX_SERIAL_NAME_LENGTH] = { '\0' };
bool has_savepoint = true;
int save = 0;
int error = NO_ERROR;
if (class_mop == NULL || owner_mop == NULL)
{
ERROR_SET_WARNING (error, ER_AU_INVALID_ARGUMENTS);
return error;
}
if (!au_is_dba_group_member (Au_user))
{
ERROR_SET_WARNING_1ARG (error, ER_AU_DBA_ONLY, "change_owner");
return error;
}
AU_DISABLE (save);
error = au_fetch_class_force (class_mop, &class_, AU_FETCH_UPDATE);
if (error != NO_ERROR)
{
ASSERT_ERROR ();
goto end;
}
if (ws_is_same_object (class_->owner, owner_mop))
{
goto end;
}
error = tran_system_savepoint (UNIQUE_SAVEPOINT_CHANGE_OWNER_WITH_RENAME);
if (error != NO_ERROR)
{
ASSERT_ERROR ();
goto end;
}
has_savepoint = true;
/* Change serial object's owner when the class has auto_increment attribute column. */
for (attr = class_->attributes; attr; attr = (SM_ATTRIBUTE *) attr->header.next)
{
if (attr->auto_increment)
{
error = au_change_serial_owner (attr->auto_increment, owner_mop, true);
if (error != NO_ERROR)
{
ASSERT_ERROR ();
goto end;
}
}
}
/* Change the owner of the class. */
class_->owner = owner_mop;
/* unique_name contains owner_name. if owner of class is changed, unique_name must be changed as well. */
class_old_name = CONST_CAST (char *, sm_ch_name ((MOBJ) class_));
/* unique_name of system class does not contain owner_name. unique_name does not need to be changed. */
if (sm_check_system_class_by_name (class_old_name))
{
error = locator_flush_class (class_mop);
if (error != NO_ERROR)
{
ASSERT_ERROR ();
goto end;
}
goto end;
}
owner_name = au_get_user_name (owner_mop);
if (!owner_name)
{
ASSERT_ERROR_AND_SET (error);
goto end;
}
sm_downcase_name (owner_name, downcase_owner_name, DB_MAX_USER_LENGTH);
db_ws_free_and_init (owner_name);
snprintf (buf, DB_MAX_IDENTIFIER_LENGTH, "%s.%s", downcase_owner_name, sm_remove_qualifier_name (class_old_name));
class_new_name = db_private_strdup (NULL, buf);
if (class_new_name == NULL)
{
ASSERT_ERROR_AND_SET (error);
goto end;
}
obj = locator_prepare_rename_class (class_mop, class_old_name, class_new_name);
if (obj == NULL)
{
ASSERT_ERROR_AND_SET (error);
goto end;
}
class_->header.ch_name = class_new_name;
if (class_->class_type == SM_CLASS_CT && class_->constraints != NULL)
{
for (constraints = class_->constraints; constraints; constraints = constraints->next)
{
if (constraints->type != SM_CONSTRAINT_INDEX
&& constraints->type != SM_CONSTRAINT_REVERSE_INDEX
&& constraints->type != SM_CONSTRAINT_UNIQUE && constraints->type != SM_CONSTRAINT_REVERSE_UNIQUE)
{
continue;
}
if (constraints->func_index_info || constraints->filter_predicate)
{
error = sm_save_constraint_info (&save_constraints, constraints);
if (error != NO_ERROR)
{
ASSERT_ERROR ();
goto end;
}
if (!save_constraints)
{
ASSERT_ERROR_AND_SET (error);
goto end;
}
saved = save_constraints;
while (saved->next)
{
saved = saved->next;
}
if (constraints->func_index_info)
{
/* recompile function index expression */
error = do_recreate_func_index_constr (NULL, saved, NULL, NULL, class_old_name, class_new_name);
if (error != NO_ERROR)
{
ASSERT_ERROR ();
goto end;
}
continue;
}
if (constraints->filter_predicate)
{
/* recompile filter index expression */
error =
do_recreate_filter_index_constr (NULL, saved->filter_predicate, NULL, class_old_name,
class_new_name);
if (error != NO_ERROR)
{
ASSERT_ERROR ();
goto end;
}
continue;
}
}
}
/* drop indexes */
for (saved = save_constraints; saved; saved = saved->next)
{
if (SM_IS_CONSTRAINT_UNIQUE_FAMILY ((SM_CONSTRAINT_TYPE) saved->constraint_type))
{
error = sm_drop_constraint (class_mop, saved->constraint_type, saved->name,
(const char **) saved->att_names, false, false);
if (error != NO_ERROR)
{
ASSERT_ERROR ();
goto end;
}
}
else
{
error = sm_drop_index (class_mop, saved->name);
if (error != NO_ERROR)
{
ASSERT_ERROR ();
goto end;
}
}
}
/* add indexes */
for (saved = save_constraints; saved != NULL; saved = saved->next)
{
error = sm_add_constraint (class_mop, saved->constraint_type, saved->name, (const char **) saved->att_names,
saved->asc_desc, saved->prefix_length, false, saved->filter_predicate,
saved->func_index_info, saved->comment, saved->index_status);
if (error != NO_ERROR)
{
ASSERT_ERROR ();
goto end;
}
}
}
error = locator_flush_class (class_mop);
if (error != NO_ERROR)
{
ASSERT_ERROR ();
goto end;
}
if (class_old_name)
{
db_private_free_and_init (NULL, class_old_name);
}
class_new_name = NULL;
end:
AU_ENABLE (save);
if (class_new_name)
{
db_private_free_and_init (NULL, class_new_name);
}
if (save_constraints)
{
sm_free_constraint_info (&save_constraints);
}
if (has_savepoint && error != NO_ERROR && error != ER_LK_UNILATERALLY_ABORTED)
{
tran_abort_upto_system_savepoint (UNIQUE_SAVEPOINT_CHANGE_OWNER_WITH_RENAME);
}
return (error);
}
/*
* au_check_class_authorization - This is similar to au_fetch_class except that
* it only checks for available authorization and
* doesn't actually return the fetched class
* return: error code
* op(in): class object
* auth(in): authorization type biits
*
* Note: Where it differs most is that it doesn't check the Au_disable flag.
* This means that it can be used when authorization
* is temporarily disabled to get the true status for a class.
* This is important for modules like the trigger manager that often
* run with authorization disabled but which need to verify access
* rights for the current user.
*/
int
au_check_class_authorization (MOP op, DB_AUTH auth)
{
int error = NO_ERROR;
SM_CLASS *class_;
int save;
/*
* It seems to be simplest to just override the Au_disable
* flag and call au_fetch_class normally. If this turns
* out to be a problem, will have to duplicate some of
* au_fetch_class here.
*/
save = Au_disable;
Au_disable = 0;
error = au_fetch_class (op, &class_, AU_FETCH_READ, auth);
Au_disable = save;
return error;
}
/*
* CLASS ACCESSING
*/
/*
* fetch_class - Work function for au_fetch_class.
* return: error code
* op(in): class or instance MOP
* return_mop(out): returned class MOP
* return_class(out): returned class structure
* fetchmode(in): desired fetch/locking mode
*/
static int
fetch_class (MOP op, MOP *return_mop, SM_CLASS **return_class, AU_FETCHMODE fetchmode, FETCH_BY fetch_by)
{
int error = NO_ERROR;
MOP classmop = NULL;
SM_CLASS *class_ = NULL;
*return_mop = NULL;
*return_class = NULL;
if (op == NULL)
{
return ER_FAILED;
}
classmop = NULL;
class_ = NULL;
if (fetch_by == BY_CLASS_MOP)
{
/* already know classmop */
classmop = op;
}
else
{
int is_class;
DB_FETCH_MODE purpose;
if (fetchmode == AU_FETCH_READ)
{
purpose = DB_FETCH_READ;
}
else
{
purpose = DB_FETCH_WRITE;
}
is_class = locator_is_class (op, purpose);
if (is_class < 0)
{
return is_class;
}
else if (is_class > 0)
{
classmop = op;
}
else
{
classmop = ws_class_mop (op);
}
}
/* the locator_fetch_class_of_instance doesn't seem to be working right now */
#if 0
if (classmop == NULL)
{
if ((error = classmop_from_instance (op, &classmop)) != NO_ERROR)
{
return (error);
}
}
#endif /* 0 */
if (classmop != NULL)
{
switch (fetchmode)
{
case AU_FETCH_READ:
class_ = (SM_CLASS *) locator_fetch_class (classmop, DB_FETCH_READ);
break;
case AU_FETCH_SCAN:
class_ = (SM_CLASS *) locator_fetch_class (classmop, DB_FETCH_SCAN);
break;
case AU_FETCH_EXCLUSIVE_SCAN:
class_ = (SM_CLASS *) locator_fetch_class (classmop, DB_FETCH_EXCLUSIVE_SCAN);
break;
case AU_FETCH_WRITE:
class_ = (SM_CLASS *) locator_fetch_class (classmop, DB_FETCH_WRITE);
break;
case AU_FETCH_UPDATE:
class_ = (SM_CLASS *) locator_update_class (classmop);
break;
}
}
else
{
switch (fetchmode)
{
case AU_FETCH_READ:
class_ = (SM_CLASS *) locator_fetch_class_of_instance (op, &classmop, DB_FETCH_READ);
break;
case AU_FETCH_SCAN:
case AU_FETCH_EXCLUSIVE_SCAN:
/* AU_FETCH_SCAN, AU_FETCH_EXCLUSIVE_SCAN are allowed only for class mops. */
assert (0);
break;
case AU_FETCH_WRITE:
class_ = (SM_CLASS *) locator_fetch_class_of_instance (op, &classmop, DB_FETCH_WRITE);
break;
case AU_FETCH_UPDATE:
class_ = (SM_CLASS *) locator_fetch_class_of_instance (op, &classmop, DB_FETCH_WRITE);
if (class_ != NULL)
{
/*
* all this appreciably does is set the dirty flag in the MOP
* should have the "dirty after getting write lock" operation
* separated
*/
class_ = (SM_CLASS *) locator_update_class (classmop);
}
break;
}
}
/* I've seen cases where locator_fetch has an error but doesn't return NULL ?? */
/* this is debug only, take out in production */
/*
* if (class_ != NULL && Db_error != NO_ERROR)
* au_log(Db_error, "Inconsistent error handling ?");
*/
if (class_ == NULL)
{
/* does it make sense to check WS_IS_DELETED here ? */
error = er_errid ();
/* !!! do we need to mask the error here ? */
/*
* if the object was deleted, set the workspace bit so we can avoid this
* in the future
*/
if (error == ER_HEAP_UNKNOWN_OBJECT)
{
if (classmop != NULL)
{
WS_SET_DELETED (classmop);
}
else
{
WS_SET_DELETED (op);
}
}
else if (error == NO_ERROR)
{
/* return NO_ERROR only if class_ is not null. */
error = ER_FAILED;
}
}
else
{
*return_mop = classmop;
*return_class = class_;
}
return error;
}
/*
* au_fetch_class_internal - helper function for au_fetch_class families
* return: error code
* op(in): class or instance
* class_ptr(out): returned pointer to class structure
* fetchmode(in): type of fetch/lock to obtain
* type(in): authorization type to check
* fetch_by(in): DONT_KNOW, BY_INSTANCE_MOP or BY_CLASS_MOP
*/
int
au_fetch_class_internal (MOP op, SM_CLASS **class_ptr, AU_FETCHMODE fetchmode, DB_AUTH type, FETCH_BY fetch_by)
{
int error = NO_ERROR;
SM_CLASS *class_;
MOP classmop;
if (class_ptr != NULL)
{
*class_ptr = NULL;
}
if (op == NULL)
{
er_set (ER_ERROR_SEVERITY, ARG_FILE_LINE, ER_OBJ_INVALID_ARGUMENTS, 0);
return ER_OBJ_INVALID_ARGUMENTS;
}
if (Au_user == NULL && !Au_disable)
{
error = ER_AU_INVALID_USER;
er_set (ER_WARNING_SEVERITY, ARG_FILE_LINE, error, 1, "");
return error;
}
if (fetchmode != AU_FETCH_READ /* not just reading */
|| WS_IS_DELETED (op) /* marked deleted */
|| op->object == NULL /* never been fetched */
|| op->class_mop != sm_Root_class_mop /* not a class */
|| op->lock < SCH_S_LOCK) /* don't have the lowest level lock */
{
/* go through the usual fetch process */
error = fetch_class (op, &classmop, &class_, fetchmode, fetch_by);
if (error != NO_ERROR)
{
return error;
}
}
else
{
/* looks like a basic read fetch, check authorization only */
classmop = op;
class_ = (SM_CLASS *) op->object;
}
/* check class representation directory */
if (OID_ISNULL (sm_ch_rep_dir ((MOBJ) class_)))
{
if (!locator_is_root (classmop))
{
error = sm_check_catalog_rep_dir (classmop, class_);
if (error != NO_ERROR)
{
return error;
}
#if !defined(NDEBUG)
if (!OID_ISTEMP (WS_OID (classmop)))
{
assert (!OID_ISNULL (sm_ch_rep_dir ((MOBJ) class_)));
}
#endif
}
}
if ((Au_disable && type != DB_AUTH_ALTER) || ! (error = check_authorization (classmop, class_, type)))
{
if (class_ptr != NULL)
{
*class_ptr = class_;
}
}
return error;
}
/*
* au_fetch_class - This is the primary function for accessing a class
* return: error code
* op(in): class or instance
* class_ptr(out): returned pointer to class structure
* fetchmode(in): type of fetch/lock to obtain
* type(in): authorization type to check
*
*/
int
au_fetch_class (MOP op, SM_CLASS **class_ptr, AU_FETCHMODE fetchmode, DB_AUTH type)
{
return au_fetch_class_internal (op, class_ptr, fetchmode, type, DONT_KNOW);
}
/*
* au_fetch_class_by_classmop - This is the primary function
* for accessing a class by an instance mop.
* return: error code
* op(in): class or instance
* class_ptr(out): returned pointer to class structure
* fetchmode(in): type of fetch/lock to obtain
* type(in): authorization type to check
*
*/
int
au_fetch_class_by_instancemop (MOP op, SM_CLASS **class_ptr, AU_FETCHMODE fetchmode, DB_AUTH type)
{
return au_fetch_class_internal (op, class_ptr, fetchmode, type, BY_INSTANCE_MOP);
}
/*
* au_fetch_class_by_classmop - This is the primary function
* for accessing a class by a class mop.
* return: error code
* op(in): class or instance
* class_ptr(out): returned pointer to class structure
* fetchmode(in): type of fetch/lock to obtain
* type(in): authorization type to check
*
*/
int
au_fetch_class_by_classmop (MOP op, SM_CLASS **class_ptr, AU_FETCHMODE fetchmode, DB_AUTH type)
{
return au_fetch_class_internal (op, class_ptr, fetchmode, type, BY_CLASS_MOP);
}
/*
* au_fetch_class_force - This is like au_fetch_class except that it will
* not check for authorization.
* return: error code
* op(in): class or instance MOP
* class(out): returned pointer to class structure
* fetchmode(in): desired operation
*
* Note: Used in a few special cases where authorization checking is
* to be disabled.
*/
int
au_fetch_class_force (MOP op, SM_CLASS **class_, AU_FETCHMODE fetchmode)
{
MOP classmop;
return (fetch_class (op, &classmop, class_, fetchmode, DONT_KNOW));
}
/*
* INSTANCE ACCESSING
*/
/*
* au_fetch_instance - This is the primary interface function for accessing
* an instance.
* return: error code
* op(in): instance MOP
* obj_ptr(in):returned pointer to instance memory
* mode(in): access type
* type(in): authorization type
* fetch_version_type(in): fetch version type
*
* Note: Fetch the object from the database if necessary, update the class
* authorization cache if necessary and check authorization for the
* desired operation.
*
* Note: If op is a VMOP au_fetch_instance will return set obj_ptr as a
* pointer to the BASE INSTANCE memory which is not the instance
* associated with op. Therefore, the object returned is not necessarily
* the contents of the supplied MOP.
*/
/*
* TODO We need to carefully examine all callers of au_fetch_instance and make
* sure they know that the object returned is not necessarily the
* contents of the supplied MOP.
*/
int
au_fetch_instance (MOP op, MOBJ *obj_ptr, AU_FETCHMODE mode, LC_FETCH_VERSION_TYPE fetch_version_type, DB_AUTH type)
{
int error = NO_ERROR;
SM_CLASS *class_;
MOP classmop;
if (Au_user == NULL && !Au_disable)
{
error = ER_AU_INVALID_USER;
er_set (ER_WARNING_SEVERITY, ARG_FILE_LINE, error, 1, "");
return error;
}
error = fetch_class (op, &classmop, &class_, AU_FETCH_READ, BY_INSTANCE_MOP);
if (error != NO_ERROR)
{
/*
* the class was deleted, make sure the instance MOP also gets
* the deleted bit set so the upper levels can depend on this
* behavior
*/
if (error == ER_HEAP_UNKNOWN_OBJECT)
{
WS_SET_DELETED (op);
}
return error;
}
if (Au_disable || ! (error = check_authorization (classmop, class_, type)))
{
error = fetch_instance (op, obj_ptr, mode, fetch_version_type);
}
return error;
}
/*
* au_fetch_instance_force - Like au_fetch_instance but doesn't check
* for authorization. Used in special circumstances
* when authorization is disabled.
* return: error code
* op(in): instance MOP
* obj_ptr(out): returned instance memory pointer
* fetchmode(in): access type
* fetch_version_type(in): fetch version type
*/
int
au_fetch_instance_force (MOP op, MOBJ *obj_ptr, AU_FETCHMODE fetchmode, LC_FETCH_VERSION_TYPE fetch_version_type)
{
return (fetch_instance (op, obj_ptr, fetchmode, fetch_version_type));
}
/*
* fetch_instance - Work function for au_fetch_instance.
* return: error code
* op(in): instance MOP
* obj_ptr(out): returned pointer to object
* fetchmode(in): desired operation
* fetch_version_type(in): fetch version type, currently used in case of
* read/write fetch
*/
static int
fetch_instance (MOP op, MOBJ *obj_ptr, AU_FETCHMODE fetchmode, LC_FETCH_VERSION_TYPE fetch_version_type)
{
int error = NO_ERROR;
MOBJ obj = NULL;
int pin;
int save;
if (obj_ptr != NULL)
{
*obj_ptr = NULL;
}
if (op == NULL)
{
er_set (ER_ERROR_SEVERITY, ARG_FILE_LINE, ER_OBJ_INVALID_ARGUMENTS, 0);
return ER_OBJ_INVALID_ARGUMENTS;
}
/* refuse attempts to fetch temporary objects */
if (op->is_temp)
{
error = ER_OBJ_INVALID_TEMP_OBJECT;
er_set (ER_ERROR_SEVERITY, ARG_FILE_LINE, error, 0);
return error;
}
/* DO NOT PUT ANY RETURNS FROM HERE UNTIL THE AU_ENABLE */
AU_DISABLE (save);
pin = ws_pin (op, 1);
if (op->is_vid)
{
switch (fetchmode)
{
case AU_FETCH_READ:
obj = vid_fetch_instance (op, DB_FETCH_READ, fetch_version_type);
break;
case AU_FETCH_WRITE:
obj = vid_fetch_instance (op, DB_FETCH_WRITE, fetch_version_type);
break;
case AU_FETCH_UPDATE:
obj = vid_upd_instance (op);
break;
case AU_FETCH_SCAN:
case AU_FETCH_EXCLUSIVE_SCAN:
er_set (ER_ERROR_SEVERITY, ARG_FILE_LINE, ER_OBJ_INVALID_ARGUMENTS, 0);
assert (0);
break;
}
}
else
{
switch (fetchmode)
{
case AU_FETCH_READ:
obj = locator_fetch_instance (op, DB_FETCH_READ, fetch_version_type);
break;
case AU_FETCH_WRITE:
obj = locator_fetch_instance (op, DB_FETCH_WRITE, fetch_version_type);
break;
case AU_FETCH_UPDATE:
obj = locator_update_instance (op);
break;
case AU_FETCH_SCAN:
case AU_FETCH_EXCLUSIVE_SCAN:
er_set (ER_ERROR_SEVERITY, ARG_FILE_LINE, ER_OBJ_INVALID_ARGUMENTS, 0);
assert (0);
break;
}
}
(void) ws_pin (op, pin);
if (obj == NULL)
{
/* does it make sense to check WS_IS_DELETED here ? */
assert (er_errid () != NO_ERROR);
error = er_errid ();
/*
* if the object was deleted, set the workspace bit so we can avoid this
* in the future
*/
if (error == ER_HEAP_UNKNOWN_OBJECT)
{
WS_SET_DELETED (op);
}
else if (error == NO_ERROR)
{
/* return NO_ERROR only if obj is not null. */
error = ER_FAILED;
}
}
else if (obj_ptr != NULL)
{
*obj_ptr = obj;
}
AU_ENABLE (save);
return error;
}
/*
* check_authorization - This is the core routine for checking authorization
* on a class.
* return: error code
* classobj(in): class MOP
* class(in): class structure
* type(in): authorization type
*
* TODO : LP64
*/
static int
check_authorization (MOP classobj, SM_CLASS *sm_class, DB_AUTH type)
{
int error = NO_ERROR;
unsigned int *bits;
/*
* Callers generally check Au_disable already to avoid the function call.
* Check it again to be safe, at this point, it isn't going to add anything.
*/
if (Au_disable)
{
int client_type = db_get_client_type ();
if (!BOOT_ADMIN_CSQL_CLIENT_TYPE (client_type) || ! (sm_class->flags & SM_CLASSFLAG_SYSTEM))
{
return NO_ERROR;
}
}
/* try to catch attempts by even the DBA to update a protected class */
if ((sm_class->flags & SM_CLASSFLAG_SYSTEM) && is_protected_class (classobj, sm_class, type))
{
error = appropriate_error (0, type);
er_set (ER_WARNING_SEVERITY, ARG_FILE_LINE, error, 0);
}
else
{
bits = Au_cache.get_cache_bits (sm_class);
if (bits == NULL)
{
assert (false);
return er_errid ();
}
if ((*bits & type) != type)
{
if (*bits == AU_CACHE_INVALID)
{
/* update the cache and try again */
error = Au_cache.update (DB_OBJECT_CLASS, classobj, sm_class);
if (error == NO_ERROR)
{
bits = Au_cache.get_cache_bits (sm_class);
if (bits == NULL)
{
return er_errid ();
}
if ((*bits & type) != type)
{
error = appropriate_error (*bits, type);
er_set (ER_WARNING_SEVERITY, ARG_FILE_LINE, error, 0);
}
}
}
else
{
error = appropriate_error (*bits, type);
er_set (ER_WARNING_SEVERITY, ARG_FILE_LINE, error, 0);
}
}
}
return error;
}
/*
* is_protected_class - This is a hack to detect attempts to modify one
* of the protected system classes.
* return: non-zero if class is protected
* classmop(in): class MOP
* class(in): class structure
* auth(in): authorization type
*
* Note: This is necessary because normally when DBA is logged in,
* authorization is effectively disabled.
* This should be handled by another "system" level of authorization.
*/
static int
is_protected_class (MOP classmop, SM_CLASS *sm_class, DB_AUTH auth)
{
int illegal = 0;
if (classmop == Au_root_class || IS_CATALOG_CLASS (sm_ch_name ((MOBJ) sm_class)))
{
illegal = auth & (AU_ALTER | AU_DELETE | AU_INSERT | AU_UPDATE | AU_INDEX);
}
else if (sm_issystem (sm_class))
{
/* if the class is a system class_, can't alter */
illegal = auth & (AU_ALTER);
}
return illegal;
}
/*
* au_get_class_privilege() -
* return: error code
* mop(in):
* auth(in):
*/
int
au_get_class_privilege (DB_OBJECT *mop, unsigned int *auth)
{
SM_CLASS *class_;
unsigned int *bits = NULL;
int error = NO_ERROR;
if (!Au_disable)
{
if (mop == NULL)
{
return ER_FAILED;
}
class_ = (SM_CLASS *) mop->object;
bits = Au_cache.get_cache_bits (class_);
if (bits == NULL)
{
return er_errid ();
}
if (*bits == AU_CACHE_INVALID)
{
error = Au_cache.update (DB_OBJECT_CLASS, mop, class_);
if (error == NO_ERROR)
{
bits = Au_cache.get_cache_bits (class_);
}
}
*auth = *bits;
}
return error;
}