mirror of
https://github.com/FirebirdSQL/firebird.git
synced 2025-01-27 20:03:03 +01:00
2174 lines
50 KiB
Plaintext
2174 lines
50 KiB
Plaintext
/*
|
|
* PROGRAM: JRD Data Definition Utility
|
|
* MODULE: dyn.e
|
|
* DESCRIPTION: Dynamic data definition
|
|
*
|
|
* The contents of this file are subject to the Interbase Public
|
|
* License Version 1.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.Inprise.com/IPL.html
|
|
*
|
|
* Software distributed under the License is distributed on an
|
|
* "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, either express
|
|
* or implied. See the License for the specific language governing
|
|
* rights and limitations under the License.
|
|
*
|
|
* The Original Code was created by Inprise Corporation
|
|
* and its predecessors. Portions created by Inprise Corporation are
|
|
* Copyright (C) Inprise Corporation.
|
|
*
|
|
* All Rights Reserved.
|
|
* Contributor(s): ______________________________________.
|
|
*
|
|
* 2001.04.20 Claudio Valderrama: Fix bug in grant/revoke by making user
|
|
* case insensitive.
|
|
* 2001.05.24 Claudio Valderrama: Move DYN_delete_role to dyn_del.e.
|
|
* 2001.06.05 John Bellardo: Renamed the revoke static function to
|
|
* revoke_permission, because there is already
|
|
* a revoke(2) function in *nix.
|
|
* 2001.06.20 Claudio Valderrama: Enable calls to DYN_delete_generator.
|
|
* 2001.10.01 Claudio Valderrama: Enable explicit GRANT...to ROLE role_name.
|
|
* and complain if the grantee ROLE doesn't exist.
|
|
* 2001.10.06 Claudio Valderrama: Forbid "NONE" from role-related operations.
|
|
* Honor explicit USER keyword in GRANTs and REVOKEs.
|
|
*
|
|
* 2002.08.10 Dmitry Yemanov: ALTER VIEW
|
|
*/
|
|
|
|
#include "firebird.h"
|
|
#include <stdio.h>
|
|
#include <string.h>
|
|
|
|
#include "../jrd/ibsetjmp.h"
|
|
#include "../jrd/common.h"
|
|
#include <stdarg.h>
|
|
#include "../jrd/jrd.h"
|
|
#include "../jrd/ods.h"
|
|
#include "../jrd/tra.h"
|
|
#include "../jrd/scl.h"
|
|
#include "../jrd/drq.h"
|
|
#include "../jrd/flags.h"
|
|
#include "../jrd/gds.h"
|
|
#include "../jrd/lls.h"
|
|
#include "../jrd/all.h"
|
|
#include "../jrd/met.h"
|
|
#include "../jrd/btr.h"
|
|
#include "../jrd/intl.h"
|
|
#include "../jrd/dyn.h"
|
|
#include "../jrd/license.h"
|
|
#include "../jrd/all_proto.h"
|
|
#include "../jrd/blb_proto.h"
|
|
#include "../jrd/cmp_proto.h"
|
|
#include "../jrd/dpm_proto.h"
|
|
#include "../jrd/dyn_proto.h"
|
|
#include "../jrd/dyn_df_proto.h"
|
|
#include "../jrd/dyn_dl_proto.h"
|
|
#include "../jrd/dyn_md_proto.h"
|
|
#include "../jrd/err_proto.h"
|
|
#include "../jrd/exe_proto.h"
|
|
#include "../jrd/gds_proto.h"
|
|
#include "../jrd/inf_proto.h"
|
|
#include "../jrd/intl_proto.h"
|
|
#include "../jrd/isc_f_proto.h"
|
|
#include "../jrd/met_proto.h"
|
|
#include "../jrd/thd_proto.h"
|
|
#include "../jrd/vio_proto.h"
|
|
#include "../jrd/sch_proto.h"
|
|
|
|
#ifdef SUPERSERVER
|
|
#define V4_THREADING
|
|
#endif
|
|
#include "../jrd/nlm_thd.h"
|
|
|
|
#define BLANK '\040'
|
|
|
|
DATABASE DB = STATIC "yachts.gdb";
|
|
|
|
|
|
|
|
static void grant(GBL, UCHAR **);
|
|
static bool grantor_can_grant_role(TDBB, GBL, TEXT *, TEXT *);
|
|
static bool grantor_can_grant(GBL, TEXT *, TEXT *, TEXT *, TEXT *, bool);
|
|
static void revoke_permission(GBL, UCHAR **);
|
|
static void store_privilege(GBL, TEXT *, TEXT *, TEXT *, TEXT *, SSHORT,
|
|
SSHORT, int);
|
|
static void set_field_class_name(GBL, TEXT *, TEXT *);
|
|
|
|
|
|
void DYN_ddl(ATT attachment, TRA transaction, USHORT length, UCHAR * ddl)
|
|
{
|
|
/**************************************
|
|
*
|
|
* D Y N _ d d l
|
|
*
|
|
**************************************
|
|
*
|
|
* Functional description
|
|
* Do meta-data.
|
|
*
|
|
**************************************/
|
|
|
|
TDBB tdbb = GET_THREAD_DATA;
|
|
|
|
#ifdef V4_THREADING
|
|
DBB dbb = tdbb->tdbb_database;
|
|
#endif
|
|
|
|
UCHAR* ptr = ddl;
|
|
|
|
if (*ptr++ != gds_dyn_version_1) {
|
|
ERR_post(gds_wrodynver, 0);
|
|
}
|
|
|
|
STATUS* status = tdbb->tdbb_status_vector;
|
|
*status++ = gds_arg_gds;
|
|
*status++ = 0;
|
|
*status = gds_arg_end;
|
|
|
|
struct gbl gbl;
|
|
gbl.gbl_transaction = transaction;
|
|
|
|
// Create a pool for DYN to operate in. It will be released when
|
|
// the routine exits.
|
|
JrdMemoryPool* old_pool = tdbb->tdbb_default;
|
|
JrdMemoryPool tempPool;
|
|
tdbb->tdbb_default = &tempPool;
|
|
|
|
try {
|
|
|
|
#if defined(SUPERSERVER) && defined(WIN_NT)
|
|
THREAD_EXIT;
|
|
THD_MUTEX_LOCK(dbb->dbb_mutexes + DBB_MUTX_dyn);
|
|
THREAD_ENTER;
|
|
#else
|
|
V4_JRD_MUTEX_LOCK(dbb->dbb_mutexes + DBB_MUTX_dyn);
|
|
#endif
|
|
|
|
VIO_start_save_point(tdbb, transaction);
|
|
transaction->tra_save_point->sav_verb_count++;
|
|
|
|
DYN_execute(&gbl, &ptr, (TEXT*)NULL_PTR, (TEXT*)NULL_PTR, (TEXT*)NULL_PTR, (TEXT*)NULL_PTR, (TEXT*)NULL_PTR);
|
|
transaction->tra_save_point->sav_verb_count--;
|
|
VIO_verb_cleanup(tdbb, transaction);
|
|
|
|
#if defined(SUPERSERVER) && defined(WIN_NT)
|
|
THD_MUTEX_UNLOCK(dbb->dbb_mutexes + DBB_MUTX_dyn);
|
|
#else
|
|
V4_JRD_MUTEX_UNLOCK(dbb->dbb_mutexes + DBB_MUTX_dyn);
|
|
#endif
|
|
|
|
}
|
|
catch (...) {
|
|
const sav* savepoint = transaction->tra_save_point;
|
|
if (savepoint && savepoint)
|
|
{
|
|
// An error during undo is very bad and has to be dealt with
|
|
// by aborting the transaction. The easiest way is to kill
|
|
// the application by calling bugcheck.
|
|
|
|
try {
|
|
VIO_verb_cleanup(tdbb, transaction);
|
|
}
|
|
catch (...) {
|
|
BUGCHECK(290); /* msg 290 error during savepoint backout */
|
|
}
|
|
}
|
|
|
|
#if defined(SUPERSERVER) && defined(WIN_NT)
|
|
THD_MUTEX_UNLOCK(dbb->dbb_mutexes + DBB_MUTX_dyn);
|
|
#else
|
|
V4_JRD_MUTEX_UNLOCK(dbb->dbb_mutexes + DBB_MUTX_dyn);
|
|
#endif
|
|
|
|
tdbb->tdbb_default = old_pool;
|
|
ERR_punt();
|
|
}
|
|
|
|
tdbb->tdbb_default = old_pool;
|
|
}
|
|
|
|
|
|
void DYN_error(USHORT status_flag,
|
|
USHORT number,
|
|
TEXT* arg1,
|
|
TEXT* arg2,
|
|
TEXT* arg3,
|
|
TEXT* arg4,
|
|
TEXT* arg5)
|
|
{
|
|
/**************************************
|
|
*
|
|
* D Y N _ e r r o r
|
|
*
|
|
**************************************
|
|
*
|
|
* Functional description
|
|
* DDL failed.
|
|
*
|
|
**************************************/
|
|
TDBB tdbb;
|
|
STATUS local_status[20], *v1, *v2, *end, arg;
|
|
|
|
|
|
tdbb = GET_THREAD_DATA;
|
|
|
|
if (tdbb->tdbb_status_vector[1] == gds_no_meta_update)
|
|
return;
|
|
|
|
TEXT error_buffer[BUFFER_MEDIUM];
|
|
|
|
if (number)
|
|
gds__msg_format(NULL_PTR, DYN_MSG_FAC, number,
|
|
sizeof(TEXT) * BUFFER_MEDIUM, error_buffer, arg1,
|
|
arg2, arg3, arg4, arg5);
|
|
|
|
v1 = local_status;
|
|
|
|
*v1++ = gds_arg_gds;
|
|
*v1++ = gds_no_meta_update;
|
|
if (number) {
|
|
*v1++ = gds_arg_gds;
|
|
*v1++ = gds_random;
|
|
*v1++ = gds_arg_string;
|
|
*v1++ = (STATUS) ERR_cstring(error_buffer);
|
|
}
|
|
if (status_flag) {
|
|
v2 = tdbb->tdbb_status_vector;
|
|
|
|
/* check every other argument for end of vector */
|
|
|
|
end = local_status + sizeof(local_status) - 1;
|
|
while (v1 < end &&
|
|
((arg = *v2++) != gds_arg_cstring || v1 + 1 < end) &&
|
|
(*v1++ = arg)) {
|
|
*v1++ = *v2++;
|
|
if (arg == gds_arg_cstring)
|
|
*v1++ = *v2++;
|
|
}
|
|
}
|
|
*v1 = gds_arg_end;
|
|
end = v1 + 1;
|
|
|
|
for (v1 = local_status, v2 = tdbb->tdbb_status_vector; v1 < end;)
|
|
*v2++ = *v1++;
|
|
}
|
|
|
|
|
|
void DYN_error_punt(USHORT status_flag,
|
|
USHORT number,
|
|
TEXT* arg1,
|
|
TEXT* arg2,
|
|
TEXT* arg3,
|
|
TEXT* arg4,
|
|
TEXT* arg5)
|
|
{
|
|
/**************************************
|
|
*
|
|
* D Y N _ e r r o r _ p u n t
|
|
*
|
|
**************************************
|
|
*
|
|
* Functional description
|
|
* DDL failed.
|
|
*
|
|
**************************************/
|
|
|
|
DYN_error(status_flag, number, arg1, arg2, arg3, arg4, arg5);
|
|
ERR_punt();
|
|
}
|
|
|
|
|
|
BOOLEAN DYN_is_it_sql_role(GBL gbl,
|
|
TEXT* input_name,
|
|
TEXT* output_name,
|
|
TDBB tdbb)
|
|
{
|
|
/**************************************
|
|
*
|
|
* D Y N _ i s _ i t _ s q l _ r o l e
|
|
*
|
|
**************************************
|
|
*
|
|
* Functional description
|
|
*
|
|
* If input_name is found in RDB$ROLES, then returns TRUE. Otherwise
|
|
* returns FALSE.
|
|
*
|
|
**************************************/
|
|
DBB dbb;
|
|
BLK request;
|
|
BOOLEAN found;
|
|
USHORT major_version, minor_original;
|
|
|
|
SET_TDBB(tdbb);
|
|
dbb = tdbb->tdbb_database;
|
|
|
|
major_version = (SSHORT) dbb->dbb_ods_version;
|
|
minor_original = (SSHORT) dbb->dbb_minor_original;
|
|
found = FALSE;
|
|
|
|
if (ENCODE_ODS(major_version, minor_original) < ODS_9_0)
|
|
return found;
|
|
|
|
request = (BLK) CMP_find_request(tdbb, drq_get_role_nm, DYN_REQUESTS);
|
|
|
|
FOR(REQUEST_HANDLE request TRANSACTION_HANDLE gbl->gbl_transaction)
|
|
X IN RDB$ROLES WITH
|
|
X.RDB$ROLE_NAME EQ input_name
|
|
if (!DYN_REQUEST(drq_get_role_nm))
|
|
DYN_REQUEST(drq_get_role_nm) = request;
|
|
|
|
found = TRUE;
|
|
DYN_terminate(X.RDB$OWNER_NAME, sizeof(X.RDB$OWNER_NAME));
|
|
strcpy(output_name, X.RDB$OWNER_NAME);
|
|
|
|
END_FOR;
|
|
|
|
if (!DYN_REQUEST(drq_get_role_nm))
|
|
DYN_REQUEST(drq_get_role_nm) = request;
|
|
|
|
return found;
|
|
}
|
|
|
|
|
|
void DYN_unsupported_verb(void)
|
|
{
|
|
/**************************************
|
|
*
|
|
* D Y N _ u n s u p p o r t e d _ v e r b
|
|
*
|
|
**************************************
|
|
*
|
|
* Functional description
|
|
* We encountered an unsupported dyn verb.
|
|
*
|
|
**************************************/
|
|
|
|
DYN_error_punt(FALSE, 2, NULL, NULL, NULL, NULL, NULL); /* msg 2: "unsupported DYN verb" */
|
|
}
|
|
|
|
|
|
void DYN_execute(
|
|
GBL gbl,
|
|
UCHAR ** ptr,
|
|
TEXT * relation_name,
|
|
TEXT * field_name,
|
|
TEXT * trigger_name,
|
|
TEXT * function_name, TEXT * procedure_name)
|
|
{
|
|
/**************************************
|
|
*
|
|
* D Y N _ e x e c u t e
|
|
*
|
|
**************************************
|
|
*
|
|
* Functional description
|
|
* Execute a dynamic ddl statement.
|
|
*
|
|
**************************************/
|
|
UCHAR verb;
|
|
|
|
switch (verb = *(*ptr)++) {
|
|
case gds_dyn_begin:
|
|
while (**ptr != gds_dyn_end)
|
|
DYN_execute(gbl, ptr, relation_name, field_name,
|
|
trigger_name, function_name, procedure_name);
|
|
++(*ptr);
|
|
break;
|
|
|
|
/* Runtime security-related dynamic DDL should not require licensing.
|
|
A placeholder case statement for SQL 3 Roles is reserved below. */
|
|
|
|
case gds_dyn_grant:
|
|
grant(gbl, ptr);
|
|
break;
|
|
|
|
case gds_dyn_revoke:
|
|
revoke_permission(gbl, ptr);
|
|
break;
|
|
|
|
/***
|
|
case gds_dyn_def_role:
|
|
create_role (gbl, ptr);
|
|
break;
|
|
***/
|
|
default:
|
|
/* make sure that the license allows metadata operations */
|
|
|
|
switch (verb) {
|
|
case gds_dyn_mod_database:
|
|
DYN_modify_database(gbl, ptr);
|
|
break;
|
|
|
|
case gds_dyn_def_rel:
|
|
case gds_dyn_def_view:
|
|
DYN_define_relation(gbl, ptr);
|
|
break;
|
|
|
|
case gds_dyn_mod_rel:
|
|
DYN_modify_relation(gbl, ptr);
|
|
break;
|
|
|
|
case gds_dyn_mod_view:
|
|
DYN_modify_view(gbl, ptr);
|
|
break;
|
|
|
|
case gds_dyn_delete_rel:
|
|
DYN_delete_relation(gbl, ptr, relation_name);
|
|
break;
|
|
|
|
case gds_dyn_def_security_class:
|
|
DYN_define_security_class(gbl, ptr);
|
|
break;
|
|
|
|
case gds_dyn_delete_security_class:
|
|
DYN_delete_security_class(gbl, ptr);
|
|
break;
|
|
|
|
case gds_dyn_def_exception:
|
|
DYN_define_exception(gbl, ptr);
|
|
break;
|
|
|
|
case gds_dyn_mod_exception:
|
|
DYN_modify_exception(gbl, ptr);
|
|
break;
|
|
|
|
case gds_dyn_del_exception:
|
|
DYN_delete_exception(gbl, ptr);
|
|
break;
|
|
|
|
case gds_dyn_def_filter:
|
|
DYN_define_filter(gbl, ptr);
|
|
break;
|
|
|
|
case gds_dyn_delete_filter:
|
|
DYN_delete_filter(gbl, ptr);
|
|
break;
|
|
|
|
case gds_dyn_def_function:
|
|
DYN_define_function(gbl, ptr);
|
|
break;
|
|
|
|
case gds_dyn_def_function_arg:
|
|
DYN_define_function_arg(gbl, ptr, function_name);
|
|
break;
|
|
|
|
case gds_dyn_delete_function:
|
|
DYN_delete_function(gbl, ptr);
|
|
break;
|
|
|
|
case gds_dyn_def_generator:
|
|
DYN_define_generator(gbl, ptr);
|
|
break;
|
|
|
|
case isc_dyn_def_sql_role:
|
|
DYN_define_role(gbl, ptr);
|
|
break;
|
|
|
|
case isc_dyn_del_sql_role:
|
|
DYN_delete_role(gbl, ptr);
|
|
break;
|
|
|
|
case gds_dyn_def_procedure:
|
|
DYN_define_procedure(gbl, ptr);
|
|
break;
|
|
|
|
case gds_dyn_mod_procedure:
|
|
DYN_modify_procedure(gbl, ptr);
|
|
break;
|
|
|
|
case gds_dyn_delete_procedure:
|
|
DYN_delete_procedure(gbl, ptr);
|
|
break;
|
|
|
|
case gds_dyn_def_parameter:
|
|
DYN_define_parameter(gbl, ptr, procedure_name);
|
|
break;
|
|
|
|
case gds_dyn_delete_parameter:
|
|
DYN_delete_parameter(gbl, ptr, procedure_name);
|
|
break;
|
|
|
|
case gds_dyn_def_shadow:
|
|
DYN_define_shadow(gbl, ptr);
|
|
break;
|
|
|
|
case gds_dyn_delete_shadow:
|
|
DYN_delete_shadow(gbl, ptr);
|
|
break;
|
|
|
|
case gds_dyn_def_trigger:
|
|
DYN_define_trigger(gbl, ptr, relation_name, NULL, FALSE);
|
|
break;
|
|
|
|
case gds_dyn_mod_trigger:
|
|
DYN_modify_trigger(gbl, ptr);
|
|
break;
|
|
|
|
case gds_dyn_delete_trigger:
|
|
DYN_delete_trigger(gbl, ptr);
|
|
break;
|
|
|
|
case gds_dyn_def_trigger_msg:
|
|
DYN_define_trigger_msg(gbl, ptr, trigger_name);
|
|
break;
|
|
|
|
case gds_dyn_mod_trigger_msg:
|
|
DYN_modify_trigger_msg(gbl, ptr, trigger_name);
|
|
break;
|
|
|
|
case gds_dyn_delete_trigger_msg:
|
|
DYN_delete_trigger_msg(gbl, ptr, trigger_name);
|
|
break;
|
|
|
|
case gds_dyn_def_global_fld:
|
|
DYN_define_global_field(gbl, ptr, relation_name, field_name);
|
|
break;
|
|
|
|
case gds_dyn_mod_global_fld:
|
|
DYN_modify_global_field(gbl, ptr, relation_name, field_name);
|
|
break;
|
|
|
|
case gds_dyn_delete_global_fld:
|
|
DYN_delete_global_field(gbl, ptr);
|
|
break;
|
|
|
|
case gds_dyn_def_local_fld:
|
|
DYN_define_local_field(gbl, ptr, relation_name, field_name);
|
|
break;
|
|
|
|
case gds_dyn_mod_local_fld:
|
|
DYN_modify_local_field(gbl, ptr, relation_name, NULL);
|
|
break;
|
|
|
|
case gds_dyn_delete_local_fld:
|
|
DYN_delete_local_field(gbl, ptr, relation_name, field_name);
|
|
break;
|
|
|
|
case isc_dyn_mod_sql_fld:
|
|
DYN_modify_sql_field(gbl, ptr, relation_name, NULL);
|
|
break;
|
|
|
|
case gds_dyn_def_sql_fld:
|
|
DYN_define_sql_field(gbl, ptr, relation_name, field_name);
|
|
break;
|
|
|
|
case gds_dyn_def_idx:
|
|
DYN_define_index(gbl, ptr, relation_name, verb, NULL, NULL, NULL,
|
|
NULL);
|
|
break;
|
|
|
|
case gds_dyn_rel_constraint:
|
|
DYN_define_constraint(gbl, ptr, relation_name, field_name);
|
|
break;
|
|
|
|
case gds_dyn_delete_rel_constraint:
|
|
DYN_delete_constraint(gbl, ptr, relation_name);
|
|
break;
|
|
|
|
case gds_dyn_mod_idx:
|
|
DYN_modify_index(gbl, ptr);
|
|
break;
|
|
|
|
case gds_dyn_delete_idx:
|
|
DYN_delete_index(gbl, ptr);
|
|
break;
|
|
|
|
case gds_dyn_view_relation:
|
|
DYN_define_view_relation(gbl, ptr, relation_name);
|
|
break;
|
|
|
|
case gds_dyn_def_dimension:
|
|
DYN_define_dimension(gbl, ptr, relation_name, field_name);
|
|
break;
|
|
|
|
case gds_dyn_delete_dimensions:
|
|
DYN_delete_dimensions(gbl, ptr, relation_name, field_name);
|
|
break;
|
|
|
|
case gds_dyn_delete_generator:
|
|
DYN_delete_generator(gbl, ptr);
|
|
break;
|
|
|
|
default:
|
|
DYN_unsupported_verb();
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
SLONG DYN_get_number(UCHAR ** ptr)
|
|
{
|
|
/**************************************
|
|
*
|
|
* D Y N _ g e t _ n u m b e r
|
|
*
|
|
**************************************
|
|
*
|
|
* Functional description
|
|
* Pick up a number and possible clear a null flag.
|
|
*
|
|
**************************************/
|
|
UCHAR *p;
|
|
USHORT length;
|
|
|
|
p = *ptr;
|
|
length = *p++;
|
|
length |= (*p++) << 8;
|
|
*ptr = p + length;
|
|
|
|
return gds__vax_integer(p, length);
|
|
}
|
|
|
|
|
|
USHORT DYN_get_string(TEXT ** ptr, TEXT * field, USHORT size, USHORT err_flag)
|
|
{
|
|
/**************************************
|
|
*
|
|
* D Y N _ g e t _ s t r i n g
|
|
*
|
|
**************************************
|
|
*
|
|
* Functional description
|
|
* Pick up a string, move to a target, and, if requested,
|
|
* set a null flag. Return length of string.
|
|
* If destination field size is too small, punt.
|
|
* Strings need enough space for null pad.
|
|
*
|
|
**************************************/
|
|
TEXT *p;
|
|
USHORT l, e, length;
|
|
|
|
e = 0;
|
|
p = *ptr;
|
|
length = (UCHAR) * p++;
|
|
length |= ((USHORT) ((UCHAR) (*p++))) << 8;
|
|
if ( (l = length) ) {
|
|
if (length >= size) {
|
|
if (err_flag)
|
|
DYN_error_punt(FALSE, 159, NULL, NULL, NULL, NULL, NULL);
|
|
/* msg 159: Name longer than database field size */
|
|
else {
|
|
l = size - 1;
|
|
e = length - l;
|
|
}
|
|
}
|
|
do
|
|
*field++ = *p++;
|
|
while (--l);
|
|
for (; e; e--)
|
|
p++;
|
|
}
|
|
|
|
*field = 0;
|
|
*ptr = p;
|
|
|
|
return length;
|
|
}
|
|
|
|
|
|
#if (defined JPN_SJIS || defined JPN_EUC)
|
|
void DYN_get_string2( TEXT ** ptr, TEXT * field, USHORT size)
|
|
{
|
|
/**************************************
|
|
*
|
|
* D Y N _ g e t _ s t r i n g 2
|
|
*
|
|
**************************************
|
|
*
|
|
* Functional description
|
|
* Pick up a string, convert to the interp of
|
|
* the engine.
|
|
* If the string expands beyond the field size, punt.
|
|
*
|
|
**************************************/
|
|
TEXT *p;
|
|
USHORT length;
|
|
USHORT from_interp;
|
|
USHORT to_interp;
|
|
DSC from, to;
|
|
|
|
to_interp = HOST_INTERP;
|
|
|
|
p = *ptr;
|
|
|
|
from_interp = *p++;
|
|
from_interp |= (*p++) << 8;
|
|
|
|
length = *p++;
|
|
length |= (*p++) << 8;
|
|
|
|
from.dsc_dtype = dtype_text;
|
|
from.dsc_scale = from_interp;
|
|
from.dsc_length = length;
|
|
from.dsc_address = (UCHAR *) p;
|
|
|
|
to.dsc_dtype = dtype_cstring;
|
|
to.dsc_scale = to_interp;
|
|
to.dsc_length = size;
|
|
to.dsc_address = (UCHAR *) field;
|
|
|
|
MOV_move(&from, &to);
|
|
|
|
p += length;
|
|
*ptr = p;
|
|
}
|
|
#endif
|
|
|
|
|
|
USHORT DYN_put_blr_blob(GBL gbl, UCHAR** ptr, GDS__QUAD* blob_id)
|
|
{
|
|
/**************************************
|
|
*
|
|
* D Y N _ p u t _ b l r _ b l o b
|
|
*
|
|
**************************************
|
|
*
|
|
* Functional description
|
|
* Write out a blr blob.
|
|
*
|
|
**************************************/
|
|
TDBB tdbb;
|
|
BLB blob;
|
|
USHORT length;
|
|
UCHAR* p;
|
|
|
|
tdbb = GET_THREAD_DATA;
|
|
|
|
p = *ptr;
|
|
length = *p++;
|
|
length |= (*p++) << 8;
|
|
|
|
if (!length) {
|
|
*ptr = p;
|
|
return length;
|
|
}
|
|
|
|
try {
|
|
blob = BLB_create(tdbb, gbl->gbl_transaction, (BID)blob_id);
|
|
BLB_put_segment(tdbb, blob, p, length);
|
|
BLB_close(tdbb, blob);
|
|
}
|
|
catch (...) {
|
|
DYN_error_punt(TRUE, 106, NULL, NULL, NULL, NULL, NULL);
|
|
/* msg 106: "Create metadata blob failed" */
|
|
}
|
|
|
|
*ptr = p + length;
|
|
|
|
return length;
|
|
}
|
|
|
|
|
|
#if (defined JPN_SJIS || defined JPN_EUC)
|
|
USHORT DYN_put_blr_blob2(GBL gbl, UCHAR ** ptr, GDS__QUAD * blob_id)
|
|
{
|
|
/**************************************
|
|
*
|
|
* D Y N _ p u t _ b l r _ b l o b 2
|
|
*
|
|
**************************************
|
|
*
|
|
* Functional description
|
|
* Write out a blob.
|
|
* Convert the string to local encoding.
|
|
* Not sure why we call this blr blob
|
|
* This routine is used to put query_header
|
|
* which is a text blob.
|
|
*
|
|
**************************************/
|
|
TDBB tdbb;
|
|
BLK blob;
|
|
USHORT length;
|
|
UCHAR *p;
|
|
USHORT bpb_length, from_interp;
|
|
UCHAR bpb[20], *p2;
|
|
|
|
tdbb = GET_THREAD_DATA;
|
|
|
|
p = *ptr;
|
|
|
|
from_interp = *p++;
|
|
from_interp |= (*p++) << 8;
|
|
|
|
length = *p++;
|
|
length |= (*p++) << 8;
|
|
|
|
if (!length) {
|
|
*ptr = p;
|
|
return length;
|
|
}
|
|
|
|
blob = NULL;
|
|
|
|
p2 = bpb;
|
|
*p2++ = gds__bpb_version1;
|
|
*p2++ = gds__bpb_source_interp;
|
|
*p2++ = 2;
|
|
*p2++ = from_interp;
|
|
*p2++ = from_interp >> 8;
|
|
bpb_length = p2 - bpb;
|
|
|
|
try {
|
|
blob =(BLK)BLB_create2( tdbb,
|
|
gbl->gbl_transaction,
|
|
blob_id,
|
|
bpb_length,
|
|
bpb);
|
|
BLB_put_segment(tdbb, blob, p, length);
|
|
BLB_close(tdbb, blob);
|
|
}
|
|
catch (...) {
|
|
DYN_error_punt(TRUE, 106, NULL, NULL, NULL, NULL, NULL);
|
|
/* msg 106: "Create metadata blob failed" */
|
|
}
|
|
|
|
*ptr = p + length;
|
|
|
|
return length;
|
|
}
|
|
#endif
|
|
|
|
|
|
USHORT DYN_put_text_blob(GBL gbl, UCHAR ** ptr, GDS__QUAD * blob_id)
|
|
{
|
|
/**************************************
|
|
*
|
|
* D Y N _ p u t _ t e x t _ b l o b
|
|
*
|
|
**************************************
|
|
*
|
|
* Functional description
|
|
* Write out a text blob.
|
|
*
|
|
**************************************/
|
|
TDBB tdbb;
|
|
USHORT length;
|
|
UCHAR *p, *end;
|
|
BLB blob;
|
|
|
|
tdbb = GET_THREAD_DATA;
|
|
|
|
p = *ptr;
|
|
length = *p++;
|
|
length |= (*p++) << 8;
|
|
|
|
if (!length) {
|
|
*ptr = p;
|
|
return length;
|
|
}
|
|
|
|
try {
|
|
blob = BLB_create(tdbb, gbl->gbl_transaction, (BID)blob_id);
|
|
|
|
for (end = p + length; p < end; p += TEXT_BLOB_LENGTH)
|
|
{
|
|
length = (p + TEXT_BLOB_LENGTH <= end) ? TEXT_BLOB_LENGTH : end - p;
|
|
BLB_put_segment(tdbb, blob, p, length);
|
|
}
|
|
BLB_close(tdbb, blob);
|
|
}
|
|
catch (...) {
|
|
DYN_error_punt(TRUE, 106, NULL, NULL, NULL, NULL, NULL);
|
|
/* msg 106: "Create metadata blob failed" */
|
|
}
|
|
|
|
*ptr = end;
|
|
|
|
return length;
|
|
}
|
|
|
|
|
|
#if (defined JPN_SJIS || defined JPN_EUC)
|
|
USHORT DYN_put_text_blob2(GBL gbl, UCHAR ** ptr, GDS__QUAD * blob_id)
|
|
{
|
|
/**************************************
|
|
*
|
|
* D Y N _ p u t _ t e x t _ b l o b 2
|
|
*
|
|
**************************************
|
|
*
|
|
* Functional description
|
|
* Write out a text blob.
|
|
* This one is similar to put_text_blob(),
|
|
* except that this one is for tagged description blobs.
|
|
*
|
|
**************************************/
|
|
TDBB tdbb;
|
|
USHORT length;
|
|
UCHAR *p, *end;
|
|
BLK blob;
|
|
USHORT bpb_length, from_interp;
|
|
UCHAR bpb[20], *p2;
|
|
|
|
tdbb = GET_THREAD_DATA;
|
|
|
|
p = *ptr;
|
|
|
|
from_interp = *p++;
|
|
from_interp |= (*p++) << 8;
|
|
|
|
length = *p++;
|
|
length |= (*p++) << 8;
|
|
|
|
if (!length) {
|
|
*ptr = p;
|
|
return length;
|
|
}
|
|
|
|
p2 = bpb;
|
|
*p2++ = gds__bpb_version1;
|
|
*p2++ = gds__bpb_source_interp;
|
|
*p2++ = 2;
|
|
*p2++ = from_interp;
|
|
*p2++ = from_interp >> 8;
|
|
bpb_length = p2 - bpb;
|
|
|
|
try {
|
|
blob = (BLK)BLB_create2(tdbb,
|
|
gbl->gbl_transaction,
|
|
blob_id,
|
|
bpb_length,
|
|
bpb);
|
|
|
|
for (end = p + length; p < end; p += TEXT_BLOB_LENGTH)
|
|
{
|
|
length = (p + TEXT_BLOB_LENGTH <= end) ? TEXT_BLOB_LENGTH : end - p;
|
|
BLB_put_segment(tdbb, blob, p, length);
|
|
}
|
|
BLB_close(tdbb, blob);
|
|
}
|
|
catch (...) {
|
|
DYN_error_punt(TRUE, 106, NULL, NULL, NULL, NULL, NULL);
|
|
/* msg 106: "Create metadata blob failed" */
|
|
}
|
|
|
|
*ptr = end;
|
|
|
|
return length;
|
|
}
|
|
#endif /* (defined JPN_SJIS || defined JPN_EUC) */
|
|
|
|
|
|
void DYN_rundown_request(BLK handle, SSHORT id)
|
|
{
|
|
/**************************************
|
|
*
|
|
* D Y N _ r u n d o w n _ r e q u e s t
|
|
*
|
|
**************************************
|
|
*
|
|
* Functional description
|
|
* Unwind a request and save it
|
|
* in the dyn internal request list.
|
|
*
|
|
**************************************/
|
|
|
|
TDBB tdbb = GET_THREAD_DATA;
|
|
DBB dbb = tdbb->tdbb_database;
|
|
|
|
#pragma FB_COMPILER_MESSAGE("TMN: FIXME! We do not have a jmp_buf anymore!")
|
|
|
|
if (!handle) {
|
|
return;
|
|
}
|
|
|
|
EXE_unwind(tdbb, (REQ)handle);
|
|
if (id >= 0 && !DYN_REQUEST(id)) {
|
|
DYN_REQUEST(id) = handle;
|
|
}
|
|
}
|
|
|
|
|
|
USHORT DYN_skip_attribute(UCHAR ** ptr)
|
|
{
|
|
/**************************************
|
|
*
|
|
* D Y N _ s k i p _ a t t r i b u t e
|
|
*
|
|
**************************************
|
|
*
|
|
* Functional description
|
|
* Skip over attribute returning length (excluding
|
|
* size of count bytes).
|
|
*
|
|
**************************************/
|
|
UCHAR *p;
|
|
USHORT length;
|
|
|
|
p = *ptr;
|
|
length = *p++;
|
|
length |= (*p++) << 8;
|
|
*ptr = p + length;
|
|
|
|
return length;
|
|
}
|
|
|
|
|
|
#if (defined JPN_SJIS || defined JPN_EUC)
|
|
USHORT DYN_skip_attribute2(UCHAR ** ptr)
|
|
{
|
|
/**************************************
|
|
*
|
|
* D Y N _ s k i p _ a t t r i b u t e 2
|
|
*
|
|
**************************************
|
|
*
|
|
* Functional description
|
|
* Skip over a tagged attribute returning length
|
|
* (excluding size of count bytes and tag).
|
|
*
|
|
**************************************/
|
|
UCHAR *p;
|
|
USHORT length;
|
|
USHORT from_interp;
|
|
|
|
p = *ptr;
|
|
|
|
from_interp = *p++;
|
|
from_interp |= (*p++) << 8;
|
|
|
|
length = *p++;
|
|
length |= (*p++) << 8;
|
|
*ptr = p + length;
|
|
|
|
return length;
|
|
}
|
|
#endif
|
|
|
|
|
|
void DYN_terminate( TEXT * string, int length)
|
|
{
|
|
/**************************************
|
|
*
|
|
* D Y N _ t e r m i n a t e
|
|
*
|
|
**************************************
|
|
*
|
|
* Functional description
|
|
* Remove trailing blanks from a string.
|
|
* Ensure that the resulting string (of size length) is
|
|
* terminated with a NULL.
|
|
*
|
|
**************************************/
|
|
TEXT *p, *q;
|
|
|
|
q = string - 1;
|
|
for (p = string; *p && --length; p++) {
|
|
if (*p != BLANK)
|
|
q = p;
|
|
}
|
|
|
|
*(q + 1) = '\0';
|
|
}
|
|
|
|
|
|
static void grant( GBL gbl, UCHAR ** ptr)
|
|
{
|
|
/**************************************
|
|
*
|
|
* g r a n t
|
|
*
|
|
**************************************
|
|
*
|
|
* Functional description
|
|
* Execute SQL grant operation.
|
|
*
|
|
**************************************/
|
|
|
|
BLK request;
|
|
//volatile SSHORT err_num;
|
|
volatile SSHORT id;
|
|
TEXT privileges[16];
|
|
TEXT object[32];
|
|
TEXT field[32];
|
|
TEXT user[32];
|
|
TEXT priv[2];
|
|
bool grant_role_stmt = false;
|
|
TEXT grantor[32];
|
|
TEXT* p;
|
|
TEXT* ptr1;
|
|
TEXT* ptr2;
|
|
|
|
TDBB tdbb = GET_THREAD_DATA;
|
|
DBB dbb = tdbb->tdbb_database;
|
|
|
|
USHORT major_version = (SSHORT) dbb->dbb_ods_version;
|
|
USHORT minor_original = (SSHORT) dbb->dbb_minor_original;
|
|
|
|
GET_STRING(ptr, privileges);
|
|
if (!strcmp(privileges, "A")) {
|
|
strcpy(privileges, ALL_PRIVILEGES);
|
|
}
|
|
|
|
object[0] = field[0] = user[0] = 0;
|
|
int options = 0;
|
|
SSHORT user_type = -1;
|
|
SSHORT obj_type = -1;
|
|
TEXT dummy_name[32];
|
|
|
|
UCHAR verb;
|
|
while ((verb = *(*ptr)++) != gds_dyn_end)
|
|
{
|
|
switch (verb) {
|
|
case gds_dyn_rel_name:
|
|
obj_type = obj_relation;
|
|
GET_STRING(ptr, object);
|
|
break;
|
|
|
|
case gds_dyn_prc_name:
|
|
obj_type = obj_procedure;
|
|
GET_STRING(ptr, object);
|
|
break;
|
|
|
|
case gds_dyn_fld_name:
|
|
GET_STRING(ptr, field);
|
|
break;
|
|
|
|
case isc_dyn_grant_user_group:
|
|
user_type = obj_user_group;
|
|
GET_STRING(ptr, user);
|
|
break;
|
|
|
|
case gds_dyn_grant_user:
|
|
{
|
|
GET_STRING(ptr, user);
|
|
DYN_terminate(user, sizeof(user));
|
|
/* This test may become obsolete as we now allow explicit ROLE keyword. */
|
|
if (DYN_is_it_sql_role(gbl, user, dummy_name, tdbb)) {
|
|
user_type = obj_sql_role;
|
|
if (!strcmp(user, "NONE")) {
|
|
DYN_error_punt(FALSE, 195, user, NULL, NULL, NULL, NULL);
|
|
/* msg 195: keyword NONE could not be used as SQL role name. */
|
|
}
|
|
}
|
|
else {
|
|
user_type = obj_user;
|
|
for (ptr1 = user; *ptr1; ptr1++) {
|
|
*ptr1 = UPPER7(*ptr1);
|
|
}
|
|
}
|
|
}
|
|
break;
|
|
|
|
case isc_dyn_grant_user_explicit:
|
|
GET_STRING(ptr, user);
|
|
DYN_terminate(user, sizeof(user));
|
|
user_type = obj_user;
|
|
for (ptr1 = user; *ptr1; ptr1++) {
|
|
*ptr1 = UPPER7(*ptr1);
|
|
}
|
|
break;
|
|
|
|
case isc_dyn_grant_role:
|
|
user_type = obj_sql_role;
|
|
GET_STRING(ptr, user);
|
|
DYN_terminate(user, sizeof(user));
|
|
if (!DYN_is_it_sql_role(gbl, user, dummy_name, tdbb)) {
|
|
DYN_error_punt(FALSE, 188, user, NULL, NULL, NULL, NULL);
|
|
/* msg 188: Role doesn't exist. */
|
|
}
|
|
if (!strcmp(user, "NONE")) {
|
|
DYN_error_punt(FALSE, 195, user, NULL, NULL, NULL, NULL);
|
|
/* msg 195: keyword NONE could not be used as SQL role name. */
|
|
}
|
|
break;
|
|
|
|
case isc_dyn_sql_role_name: /* role name in role_name_list */
|
|
if (ENCODE_ODS(major_version, minor_original) < ODS_9_0) {
|
|
DYN_error_punt(FALSE, 196, NULL, NULL, NULL, NULL, NULL);
|
|
}
|
|
else {
|
|
obj_type = obj_sql_role;
|
|
GET_STRING(ptr, object);
|
|
grant_role_stmt = true;
|
|
DYN_terminate(object, sizeof(object));
|
|
if (!strcmp (object, "NONE")) {
|
|
DYN_error_punt(FALSE, 195, object, NULL, NULL, NULL, NULL);
|
|
/* msg 195: keyword NONE could not be used as SQL role name. */
|
|
}
|
|
}
|
|
break;
|
|
|
|
case gds_dyn_grant_proc:
|
|
user_type = obj_procedure;
|
|
GET_STRING(ptr, user);
|
|
break;
|
|
|
|
case gds_dyn_grant_trig:
|
|
user_type = obj_trigger;
|
|
GET_STRING(ptr, user);
|
|
break;
|
|
|
|
case gds_dyn_grant_view:
|
|
user_type = obj_view;
|
|
GET_STRING(ptr, user);
|
|
break;
|
|
|
|
case gds_dyn_grant_options:
|
|
case isc_dyn_grant_admin_options:
|
|
options = DYN_get_number(ptr);
|
|
break;
|
|
|
|
default:
|
|
DYN_unsupported_verb();
|
|
}
|
|
}
|
|
|
|
|
|
try {
|
|
|
|
request = (BLK)CMP_find_request(tdbb,
|
|
(USHORT)(field[0] ? drq_l_grant1 : drq_l_grant2),
|
|
DYN_REQUESTS);
|
|
for (p = privileges; *p; p++)
|
|
{
|
|
bool duplicate = false;
|
|
priv[0] = *p;
|
|
priv[1] = 0;
|
|
if (field[0])
|
|
{
|
|
id = drq_l_grant1;
|
|
FOR(REQUEST_HANDLE request TRANSACTION_HANDLE gbl->gbl_transaction)
|
|
PRIV IN RDB$USER_PRIVILEGES WITH
|
|
PRIV.RDB$RELATION_NAME EQ object AND
|
|
PRIV.RDB$OBJECT_TYPE = obj_type AND
|
|
PRIV.RDB$PRIVILEGE EQ priv AND
|
|
PRIV.RDB$USER = user AND
|
|
PRIV.RDB$USER_TYPE = user_type AND
|
|
PRIV.RDB$GRANTOR EQ UPPERCASE(RDB$USER_NAME) AND
|
|
PRIV.RDB$FIELD_NAME EQ field
|
|
if (!DYN_REQUEST(drq_l_grant1)) {
|
|
DYN_REQUEST(drq_l_grant1) = request;
|
|
}
|
|
|
|
if ((PRIV.RDB$GRANT_OPTION.NULL) ||
|
|
(PRIV.RDB$GRANT_OPTION) ||
|
|
(PRIV.RDB$GRANT_OPTION == options))
|
|
{
|
|
duplicate = true;
|
|
}
|
|
else
|
|
{
|
|
ERASE PRIV; /* has to be 0 and options == 1 */
|
|
}
|
|
END_FOR;
|
|
if (!DYN_REQUEST(drq_l_grant1))
|
|
{
|
|
DYN_REQUEST(drq_l_grant1) = request;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
id = drq_l_grant2;
|
|
FOR(REQUEST_HANDLE request TRANSACTION_HANDLE gbl->gbl_transaction)
|
|
PRIV IN RDB$USER_PRIVILEGES WITH
|
|
PRIV.RDB$RELATION_NAME EQ object AND
|
|
PRIV.RDB$OBJECT_TYPE = obj_type AND
|
|
PRIV.RDB$PRIVILEGE EQ priv AND
|
|
PRIV.RDB$USER = user AND
|
|
PRIV.RDB$USER_TYPE = user_type AND
|
|
PRIV.RDB$GRANTOR EQ UPPERCASE(RDB$USER_NAME) AND
|
|
PRIV.RDB$FIELD_NAME MISSING
|
|
if (!DYN_REQUEST(drq_l_grant2))
|
|
DYN_REQUEST(drq_l_grant2) = request;
|
|
|
|
if ((PRIV.RDB$GRANT_OPTION.NULL) ||
|
|
(PRIV.RDB$GRANT_OPTION) ||
|
|
(PRIV.RDB$GRANT_OPTION == options))
|
|
{
|
|
duplicate = true;
|
|
}
|
|
else
|
|
{
|
|
ERASE PRIV; /* has to be 0 and options == 1 */
|
|
}
|
|
END_FOR;
|
|
if (!DYN_REQUEST(drq_l_grant2))
|
|
{
|
|
DYN_REQUEST(drq_l_grant2) = request;
|
|
}
|
|
}
|
|
|
|
if (duplicate) {
|
|
continue;
|
|
}
|
|
|
|
if (grant_role_stmt)
|
|
{
|
|
if (ENCODE_ODS(major_version, minor_original) < ODS_9_0)
|
|
{
|
|
DYN_error_punt(FALSE, 196, NULL, NULL, NULL, NULL, NULL);
|
|
}
|
|
id = drq_get_role_nm;
|
|
|
|
for (ptr1 = tdbb->tdbb_attachment->att_user->usr_user_name,
|
|
ptr2 = grantor; *ptr1; ptr1++, ptr2++)
|
|
{
|
|
*ptr2 = UPPER7(*ptr1);
|
|
}
|
|
*ptr2 = '\0';
|
|
|
|
if (!grantor_can_grant_role(tdbb, gbl, grantor, object)) {
|
|
// ERR_punt();
|
|
goto do_punt;
|
|
}
|
|
|
|
if (user_type == obj_sql_role) {
|
|
/****************************************************
|
|
**
|
|
** temporary restriction. This should be removed once
|
|
** GRANT role1 TO rolex is supported and this message
|
|
** could be reused for blocking cycles of role grants
|
|
**
|
|
*****************************************************/
|
|
DYN_error_punt(FALSE, 192, user, NULL, NULL, NULL, NULL);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
/* In the case where the object is a view, then the grantor must have
|
|
some kind of grant privileges on the base table(s)/view(s). If the
|
|
grantor is the owner of the view, then we have to explicitely check
|
|
this because the owner of a view by default has grant privileges on
|
|
his own view. If the grantor is not the owner of the view, then the
|
|
base table/view grant privilege checks were made when the grantor
|
|
got its grant privilege on the view and no further checks are
|
|
necessary. */
|
|
|
|
if (!obj_type)
|
|
{ /* relation or view because we cannot distinguish at this point. */
|
|
id = drq_gcg1;
|
|
if (!grantor_can_grant(gbl,
|
|
tdbb->tdbb_attachment->att_user->usr_user_name,
|
|
priv,
|
|
object,
|
|
field,
|
|
true))
|
|
{
|
|
// grantor_can_grant has moved the error string already.
|
|
// just punt back to the setjump
|
|
// ERR_punt();
|
|
goto do_punt;
|
|
}
|
|
}
|
|
}
|
|
|
|
id = drq_s_grant;
|
|
store_privilege(gbl, object, user, field, p, user_type, obj_type,
|
|
options);
|
|
} // for (...)
|
|
|
|
} // try
|
|
catch (...) {
|
|
/* we need to rundown as we have to set the env.
|
|
But in case the error is from store_priveledge we have already
|
|
unwound the request so passing that as null */
|
|
BLK req1 = (id == drq_s_grant || id == drq_gcg1) ? NULL : request;
|
|
DYN_rundown_request(req1, -1);
|
|
if (id == drq_l_grant1)
|
|
{
|
|
DYN_error_punt(TRUE, 77, NULL, NULL, NULL, NULL, NULL);
|
|
// msg 77: "SELECT RDB$USER_PRIVILEGES failed in grant"
|
|
}
|
|
else if (id == drq_l_grant2)
|
|
{
|
|
DYN_error_punt(TRUE, 78, NULL, NULL, NULL, NULL, NULL);
|
|
// msg 78: "SELECT RDB$USER_PRIVILEGES failed in grant"
|
|
}
|
|
else if (id == drq_s_grant || id == drq_gcg1)
|
|
{
|
|
ERR_punt();
|
|
// store_priviledge || grantor_can_grant error already handled,
|
|
// just bail out
|
|
} else if (id == drq_get_role_nm) {
|
|
ERR_punt();
|
|
} else {
|
|
assert(id == drq_gcg1);
|
|
DYN_error_punt(TRUE, 78, NULL, NULL, NULL, NULL, NULL);
|
|
// msg 78: "SELECT RDB$USER_PRIVILEGES failed in grant"
|
|
}
|
|
}
|
|
|
|
return;
|
|
|
|
do_punt: // ugly, rethink logic of this function
|
|
ERR_punt();
|
|
}
|
|
|
|
|
|
static bool grantor_can_grant( GBL gbl,
|
|
TEXT* grantor,
|
|
TEXT* privilege,
|
|
TEXT* relation_name,
|
|
TEXT* field_name,
|
|
bool top_level)
|
|
{
|
|
/**************************************
|
|
*
|
|
* g r a n t o r _ c a n _ g r a n t
|
|
*
|
|
**************************************
|
|
*
|
|
* Functional description
|
|
* return: TRUE is the grantor has grant privilege on the relation/field.
|
|
* FALSE otherwise.
|
|
*
|
|
**************************************/
|
|
|
|
TDBB tdbb;
|
|
DBB dbb;
|
|
/* Remember the grant option for non field-specific user-privileges, and the
|
|
grant option for the user-privileges for the input field.
|
|
-1 = no privilege found (yet)
|
|
0 = privilege without grant option found
|
|
1 = privilege with grant option found */
|
|
SSHORT go_rel = -1;
|
|
SSHORT go_fld = -1;
|
|
BLK request;
|
|
BOOLEAN sql_relation = FALSE;
|
|
BOOLEAN relation_exists = FALSE;
|
|
BOOLEAN field_exists = FALSE;
|
|
BOOLEAN grantor_is_owner = FALSE;
|
|
volatile USHORT err_num;
|
|
|
|
tdbb = GET_THREAD_DATA;
|
|
dbb = tdbb->tdbb_database;
|
|
|
|
/* Verify that the input relation exists. */
|
|
|
|
request = (BLK) CMP_find_request(tdbb, drq_gcg4, DYN_REQUESTS);
|
|
|
|
|
|
try {
|
|
|
|
err_num = 182; /* for the longjump */
|
|
/* SELECT RDB$RELATIONS failed in grant */
|
|
FOR(REQUEST_HANDLE request TRANSACTION_HANDLE gbl->gbl_transaction)
|
|
REL IN RDB$RELATIONS WITH
|
|
REL.RDB$RELATION_NAME = relation_name relation_exists = TRUE;
|
|
if ((!REL.RDB$FLAGS.NULL) && (REL.RDB$FLAGS & REL_sql))
|
|
sql_relation = TRUE;
|
|
if (!DYN_REQUEST(drq_gcg4))
|
|
DYN_REQUEST(drq_gcg4) = request;
|
|
END_FOR;
|
|
if (!DYN_REQUEST(drq_gcg4))
|
|
DYN_REQUEST(drq_gcg4) = request;
|
|
if (!relation_exists) {
|
|
DYN_error(FALSE, 175, relation_name, NULL, NULL, NULL, NULL);
|
|
/* table/view .. does not exist */
|
|
return false;
|
|
}
|
|
|
|
/* Verify the the input field exists. */
|
|
|
|
if (field_name[0])
|
|
{
|
|
err_num = 183;
|
|
/* SELECT RDB$RELATION_FIELDS failed in grant */
|
|
request = (BLK) CMP_find_request(tdbb, drq_gcg5, DYN_REQUESTS);
|
|
FOR(REQUEST_HANDLE request TRANSACTION_HANDLE gbl->gbl_transaction)
|
|
G_FLD IN RDB$RELATION_FIELDS WITH
|
|
G_FLD.RDB$RELATION_NAME = relation_name AND
|
|
G_FLD.RDB$FIELD_NAME = field_name if (!DYN_REQUEST(drq_gcg5))
|
|
DYN_REQUEST(drq_gcg5) = request;
|
|
field_exists = TRUE;
|
|
END_FOR;
|
|
if (!DYN_REQUEST(drq_gcg5))
|
|
DYN_REQUEST(drq_gcg5) = request;
|
|
if (!field_exists) {
|
|
DYN_error(FALSE, 176, field_name, relation_name, NULL, NULL,
|
|
NULL);
|
|
/* column .. does not exist in table/view .. */
|
|
return false;
|
|
}
|
|
}
|
|
|
|
/* If the current user is locksmith - allow all grants to occur */
|
|
|
|
if (tdbb->tdbb_attachment->att_user->usr_flags & USR_locksmith) {
|
|
return true;
|
|
}
|
|
|
|
/* If this is a non-sql table, then the owner will probably not have any
|
|
entries in the rdb$user_privileges table. Give the owner of a GDML
|
|
table all privileges. */
|
|
err_num = 184;
|
|
/* SELECT RDB$RELATIONS/RDB$OWNER_NAME failed in grant */
|
|
|
|
request = (BLK) CMP_find_request(tdbb, drq_gcg2, DYN_REQUESTS);
|
|
FOR(REQUEST_HANDLE request TRANSACTION_HANDLE gbl->gbl_transaction)
|
|
REL IN RDB$RELATIONS WITH
|
|
REL.RDB$RELATION_NAME = relation_name AND
|
|
REL.RDB$OWNER_NAME = UPPERCASE(grantor)
|
|
if (!DYN_REQUEST(drq_gcg2))
|
|
DYN_REQUEST(drq_gcg2) = request;
|
|
grantor_is_owner = TRUE;
|
|
END_FOR;
|
|
if (!DYN_REQUEST(drq_gcg2))
|
|
DYN_REQUEST(drq_gcg2) = request;
|
|
if (!sql_relation && grantor_is_owner) {
|
|
return true;
|
|
}
|
|
|
|
/* Verify that the grantor has the grant option for this relation/field
|
|
in the rdb$user_privileges. If not, then we don't need to look further. */
|
|
|
|
err_num = 185;
|
|
/* SELECT RDB$USER_PRIVILEGES failed in grant */
|
|
|
|
request = (BLK) CMP_find_request(tdbb, drq_gcg1, DYN_REQUESTS);
|
|
FOR(REQUEST_HANDLE request TRANSACTION_HANDLE gbl->gbl_transaction)
|
|
PRV IN RDB$USER_PRIVILEGES WITH
|
|
PRV.RDB$USER = UPPERCASE(grantor) AND
|
|
PRV.RDB$USER_TYPE = obj_user AND
|
|
PRV.RDB$RELATION_NAME = relation_name AND
|
|
PRV.RDB$OBJECT_TYPE = obj_relation AND
|
|
PRV.RDB$PRIVILEGE = privilege if (!DYN_REQUEST(drq_gcg1))
|
|
DYN_REQUEST(drq_gcg1) = request;
|
|
|
|
if (PRV.RDB$FIELD_NAME.NULL) {
|
|
if (PRV.RDB$GRANT_OPTION.NULL || !PRV.RDB$GRANT_OPTION)
|
|
go_rel = 0;
|
|
else if (go_rel)
|
|
go_rel = 1;
|
|
}
|
|
else {
|
|
if (PRV.RDB$GRANT_OPTION.NULL || !PRV.RDB$GRANT_OPTION) {
|
|
DYN_terminate(PRV.RDB$FIELD_NAME, sizeof(PRV.RDB$FIELD_NAME));
|
|
if (field_name[0] && !strcmp(field_name, PRV.RDB$FIELD_NAME))
|
|
go_fld = 0;
|
|
}
|
|
else
|
|
{
|
|
DYN_terminate(PRV.RDB$FIELD_NAME, sizeof(PRV.RDB$FIELD_NAME));
|
|
if (field_name[0] && !strcmp(field_name, PRV.RDB$FIELD_NAME))
|
|
go_fld = 1;
|
|
}
|
|
}
|
|
END_FOR;
|
|
if (!DYN_REQUEST(drq_gcg1))
|
|
{
|
|
DYN_REQUEST(drq_gcg1) = request;
|
|
}
|
|
|
|
if (field_name[0])
|
|
{
|
|
if (go_fld == 0)
|
|
{
|
|
DYN_error(FALSE,
|
|
(USHORT)(top_level ? 167 : 168),
|
|
privilege,
|
|
field_name,
|
|
relation_name,
|
|
NULL,
|
|
NULL);
|
|
/* no grant option for privilege .. on column .. of [base] table/view .. */
|
|
return false;
|
|
}
|
|
else if (go_fld == -1)
|
|
{
|
|
if (go_rel == 0)
|
|
{
|
|
DYN_error(FALSE,
|
|
(USHORT)(top_level ? 169 : 170),
|
|
privilege,
|
|
relation_name,
|
|
field_name,
|
|
NULL,
|
|
NULL);
|
|
/* no grant option for privilege .. on [base] table/view .. (for column ..) */
|
|
return false;
|
|
}
|
|
else if (go_rel == -1)
|
|
{
|
|
DYN_error(FALSE,
|
|
(USHORT)(top_level ? 171 : 172),
|
|
privilege,
|
|
relation_name,
|
|
field_name,
|
|
NULL,
|
|
NULL);
|
|
/* no .. privilege with grant option on [base] table/view .. (for column ..) */
|
|
return false;
|
|
}
|
|
}
|
|
}
|
|
else
|
|
{
|
|
if (go_rel == 0)
|
|
{
|
|
DYN_error(FALSE, 173, privilege, relation_name, NULL, NULL, NULL);
|
|
/* no grant option for privilege .. on table/view .. */
|
|
return false;
|
|
}
|
|
else if (go_rel == -1)
|
|
{
|
|
DYN_error(FALSE, 174, privilege, relation_name, NULL, NULL, NULL);
|
|
/* no .. privilege with grant option on table/view .. */
|
|
return false;
|
|
}
|
|
}
|
|
|
|
/* If the grantor is not the owner of the relation, then we don't need to
|
|
check the base table(s)/view(s) because that check was performed when
|
|
the grantor was given its privileges. */
|
|
|
|
if (!grantor_is_owner) {
|
|
return true;
|
|
}
|
|
|
|
/* Find all the base fields/relations and check for the correct
|
|
grant privileges on them. */
|
|
|
|
err_num = 186;
|
|
/* SELECT RDB$VIEW_RELATIONS/RDB$RELATION_FIELDS/... failed in grant */
|
|
|
|
request = (BLK) CMP_find_request(tdbb, drq_gcg3, DYN_REQUESTS);
|
|
FOR(REQUEST_HANDLE request TRANSACTION_HANDLE gbl->gbl_transaction)
|
|
G_FLD IN RDB$RELATION_FIELDS CROSS
|
|
G_VIEW IN RDB$VIEW_RELATIONS WITH
|
|
G_FLD.RDB$RELATION_NAME = relation_name AND
|
|
G_FLD.RDB$BASE_FIELD NOT MISSING AND
|
|
G_VIEW.RDB$VIEW_NAME EQ G_FLD.RDB$RELATION_NAME AND
|
|
G_VIEW.RDB$VIEW_CONTEXT EQ G_FLD.RDB$VIEW_CONTEXT
|
|
if (!DYN_REQUEST(drq_gcg3)) {
|
|
DYN_REQUEST(drq_gcg3) = request;
|
|
}
|
|
DYN_terminate(G_FLD.RDB$BASE_FIELD, sizeof(G_FLD.RDB$BASE_FIELD));
|
|
DYN_terminate(G_FLD.RDB$FIELD_NAME, sizeof(G_FLD.RDB$FIELD_NAME));
|
|
DYN_terminate(G_VIEW.RDB$RELATION_NAME,
|
|
sizeof(G_VIEW.RDB$RELATION_NAME));
|
|
|
|
if (field_name[0])
|
|
{
|
|
if (!strcmp(field_name, G_FLD.RDB$FIELD_NAME))
|
|
if (!grantor_can_grant
|
|
(gbl, grantor, privilege, G_VIEW.RDB$RELATION_NAME,
|
|
G_FLD.RDB$BASE_FIELD, FALSE)) {
|
|
return false;
|
|
}
|
|
}
|
|
else {
|
|
if (!grantor_can_grant(gbl,
|
|
grantor,
|
|
privilege,
|
|
G_VIEW.RDB$RELATION_NAME,
|
|
G_FLD.RDB$BASE_FIELD,
|
|
false))
|
|
{
|
|
return false;
|
|
}
|
|
}
|
|
END_FOR;
|
|
if (!DYN_REQUEST(drq_gcg3))
|
|
DYN_REQUEST(drq_gcg3) = request;
|
|
|
|
// all done.
|
|
|
|
} // try
|
|
catch (...) {
|
|
DYN_rundown_request(request, -1);
|
|
DYN_error_punt(TRUE, err_num, NULL, NULL, NULL, NULL, NULL);
|
|
/* msg 77: "SELECT RDB$USER_PRIVILEGES failed in grant" */
|
|
|
|
return false;
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
|
|
static bool grantor_can_grant_role( TDBB tdbb,
|
|
GBL gbl,
|
|
TEXT* grantor,
|
|
TEXT* role_name)
|
|
{
|
|
/**************************************
|
|
*
|
|
* g r a n t o r _ c a n _ g r a n t _ r o l e
|
|
*
|
|
**************************************
|
|
*
|
|
* Functional description
|
|
*
|
|
* return: TRUE if the grantor has admin privilege on the role.
|
|
* FALSE otherwise.
|
|
*
|
|
**************************************/
|
|
|
|
bool grantable = false;
|
|
TEXT owner[32];
|
|
|
|
SET_TDBB(tdbb);
|
|
DBB dbb = tdbb->tdbb_database;
|
|
|
|
if (tdbb->tdbb_attachment->att_user->usr_flags & USR_locksmith) {
|
|
return true;
|
|
}
|
|
|
|
// Fetch the name of the owner of the ROLE
|
|
if (DYN_is_it_sql_role(gbl, role_name, owner, tdbb))
|
|
{
|
|
// The owner of the ROLE can always grant membership
|
|
if (strcmp(owner, grantor) == 0) {
|
|
return true;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
/****************************************************
|
|
**
|
|
** role name not exist.
|
|
**
|
|
*****************************************************/
|
|
DYN_error(FALSE, 188, role_name, NULL, NULL, NULL, NULL);
|
|
return false;
|
|
}
|
|
|
|
BLK request = (BLK) CMP_find_request(tdbb, drq_get_role_au, DYN_REQUESTS);
|
|
|
|
// The 'grantor' is not the owner of the ROLE, see if they
|
|
// have admin privilege on the role
|
|
FOR(REQUEST_HANDLE request TRANSACTION_HANDLE gbl->gbl_transaction)
|
|
PRV IN RDB$USER_PRIVILEGES WITH
|
|
PRV.RDB$USER = UPPERCASE(grantor) AND
|
|
PRV.RDB$USER_TYPE = obj_user AND
|
|
PRV.RDB$RELATION_NAME EQ role_name AND
|
|
PRV.RDB$OBJECT_TYPE = obj_sql_role AND
|
|
PRV.RDB$PRIVILEGE EQ "M"
|
|
if (!DYN_REQUEST(drq_get_role_au)) {
|
|
DYN_REQUEST(drq_get_role_au) = request;
|
|
}
|
|
|
|
if (PRV.RDB$GRANT_OPTION == 2) {
|
|
grantable = true;
|
|
} else {
|
|
/****************************************************
|
|
**
|
|
** user have no admin option.
|
|
**
|
|
*****************************************************/
|
|
DYN_error(FALSE, 189, grantor, role_name, NULL, NULL, NULL);
|
|
return false;
|
|
}
|
|
|
|
END_FOR;
|
|
|
|
if (!DYN_REQUEST(drq_get_role_au)) {
|
|
DYN_REQUEST(drq_get_role_au) = request;
|
|
}
|
|
|
|
if (!grantable) {
|
|
/****************************************************
|
|
**
|
|
** user is not a member of the role.
|
|
**
|
|
*****************************************************/
|
|
DYN_error(FALSE, 190, grantor, role_name, NULL, NULL, NULL);
|
|
return false;
|
|
}
|
|
|
|
return grantable;
|
|
}
|
|
|
|
|
|
static void revoke_permission(GBL gbl, UCHAR ** ptr)
|
|
{
|
|
/**************************************
|
|
*
|
|
* r e v o k e _ p e r m i s s i o n
|
|
*
|
|
**************************************
|
|
*
|
|
* Functional description
|
|
* Revoke some privileges.
|
|
*
|
|
* Note: According to SQL II, section 11.37, pg 280,
|
|
* general rules 8 & 9,
|
|
* if the specified priviledge for the specified user
|
|
* does not exist, it is not an exception error condition
|
|
* but a completion condition. Since V4.0 does not support
|
|
* completion conditions (warnings) we do not return
|
|
* any indication that the revoke operation didn't do
|
|
* anything.
|
|
* 1994-August-2 Rich Damon & David Schnepper
|
|
*
|
|
**************************************/
|
|
TDBB tdbb;
|
|
DBB dbb;
|
|
BLK request;
|
|
//BLK old_request;
|
|
volatile USHORT old_id, id;
|
|
UCHAR verb;
|
|
SSHORT user_type, obj_type;
|
|
TEXT privileges[16], object[32], field[32], user[32], *p, *q, temp[2];
|
|
USHORT all_privs = FALSE;
|
|
int options;
|
|
USHORT grant_erased;
|
|
USR revoking_user;
|
|
TEXT revoking_user_name[32], dummy_name[32];
|
|
//TEXT grantor[32], *ptr2;
|
|
TEXT *ptr1;
|
|
USHORT major_version, minor_original;
|
|
|
|
|
|
tdbb = GET_THREAD_DATA;
|
|
dbb = tdbb->tdbb_database;
|
|
|
|
major_version = (SSHORT) dbb->dbb_ods_version;
|
|
minor_original = (SSHORT) dbb->dbb_minor_original;
|
|
|
|
/* Stash away a copy of the revoker's name, in uppercase form */
|
|
|
|
revoking_user = tdbb->tdbb_attachment->att_user;
|
|
for (p = revoking_user->usr_user_name, q = revoking_user_name; *p;
|
|
p++, q++)
|
|
*q = UPPER7(*p);
|
|
*q = 0;
|
|
|
|
GET_STRING(ptr, privileges);
|
|
if (!strcmp(privileges, "A")) {
|
|
strcpy(privileges, ALL_PRIVILEGES);
|
|
all_privs = TRUE;
|
|
}
|
|
|
|
object[0] = field[0] = user[0] = 0;
|
|
obj_type = user_type = -1;
|
|
options = 0;
|
|
|
|
while ((verb = *(*ptr)++) != gds_dyn_end)
|
|
switch (verb) {
|
|
case gds_dyn_rel_name:
|
|
obj_type = obj_relation;
|
|
GET_STRING(ptr, object);
|
|
break;
|
|
|
|
case gds_dyn_prc_name:
|
|
obj_type = obj_procedure;
|
|
GET_STRING(ptr, object);
|
|
break;
|
|
|
|
case gds_dyn_fld_name:
|
|
GET_STRING(ptr, field);
|
|
break;
|
|
|
|
case isc_dyn_grant_user_group:
|
|
user_type = obj_user_group;
|
|
GET_STRING(ptr, user);
|
|
break;
|
|
|
|
case gds_dyn_grant_user:
|
|
GET_STRING(ptr, user);
|
|
DYN_terminate(user, sizeof(user));
|
|
/* This test may become obsolete as we now allow explicit ROLE keyword. */
|
|
if (DYN_is_it_sql_role(gbl, user, dummy_name, tdbb)) {
|
|
user_type = obj_sql_role;
|
|
if (!strcmp(user, "NONE")) {
|
|
DYN_error_punt(FALSE, 195, user, NULL, NULL, NULL, NULL);
|
|
/* msg 195: keyword NONE could not be used as SQL role name. */
|
|
}
|
|
}
|
|
else {
|
|
user_type = obj_user;
|
|
for (ptr1 = user; *ptr1; ptr1++) {
|
|
*ptr1 = UPPER7(*ptr1);
|
|
}
|
|
}
|
|
break;
|
|
|
|
case isc_dyn_grant_user_explicit:
|
|
GET_STRING(ptr, user);
|
|
DYN_terminate(user, sizeof(user));
|
|
user_type = obj_user;
|
|
for (ptr1 = user; *ptr1; ptr1++) {
|
|
*ptr1 = UPPER7(*ptr1);
|
|
}
|
|
break;
|
|
|
|
case isc_dyn_grant_role:
|
|
user_type = obj_sql_role;
|
|
GET_STRING(ptr, user);
|
|
DYN_terminate(user, sizeof(user));
|
|
if (!DYN_is_it_sql_role(gbl, user, dummy_name, tdbb)) {
|
|
DYN_error_punt(FALSE, 188, user, NULL, NULL, NULL, NULL);
|
|
/* msg 188: Role doesn't exist. */
|
|
}
|
|
if (!strcmp(user, "NONE")) {
|
|
DYN_error_punt(FALSE, 195, user, NULL, NULL, NULL, NULL);
|
|
/* msg 195: keyword NONE could not be used as SQL role name. */
|
|
}
|
|
break;
|
|
|
|
case isc_dyn_sql_role_name: /* role name in role_name_list */
|
|
if (ENCODE_ODS(major_version, minor_original) < ODS_9_0) {
|
|
DYN_error_punt(FALSE, 196, NULL, NULL, NULL, NULL, NULL);
|
|
}
|
|
else {
|
|
obj_type = obj_sql_role;
|
|
GET_STRING(ptr, object);
|
|
DYN_terminate(object, sizeof(object));
|
|
/* CVC: Make this a warning in the future.
|
|
if (!strcmp(object, "NONE"))
|
|
DYN_error_punt(FALSE, 195, object, NULL, NULL, NULL, NULL);
|
|
*/
|
|
/* msg 195: keyword NONE could not be used as SQL role name. */
|
|
}
|
|
break;
|
|
|
|
case gds_dyn_grant_proc:
|
|
user_type = obj_procedure;
|
|
GET_STRING(ptr, user);
|
|
break;
|
|
|
|
case gds_dyn_grant_trig:
|
|
user_type = obj_trigger;
|
|
GET_STRING(ptr, user);
|
|
break;
|
|
|
|
case gds_dyn_grant_view:
|
|
user_type = obj_view;
|
|
GET_STRING(ptr, user);
|
|
break;
|
|
|
|
case gds_dyn_grant_options:
|
|
options = DYN_get_number(ptr);
|
|
break;
|
|
|
|
default:
|
|
DYN_unsupported_verb();
|
|
}
|
|
|
|
request = (BLK)CMP_find_request(tdbb,
|
|
(USHORT)(field[0] ? drq_e_grant1 : drq_e_grant2),
|
|
DYN_REQUESTS);
|
|
id = field[0] ? drq_e_grant1 : drq_e_grant2;
|
|
|
|
try {
|
|
|
|
temp[1] = 0;
|
|
for (p = privileges; (temp[0] = *p); p++)
|
|
{
|
|
grant_erased = FALSE;
|
|
|
|
if (field[0])
|
|
{
|
|
FOR(REQUEST_HANDLE request TRANSACTION_HANDLE gbl->gbl_transaction)
|
|
PRIV IN RDB$USER_PRIVILEGES WITH
|
|
PRIV.RDB$PRIVILEGE EQ temp AND
|
|
PRIV.RDB$RELATION_NAME EQ object AND
|
|
PRIV.RDB$OBJECT_TYPE = obj_type AND
|
|
PRIV.RDB$USER = user AND
|
|
PRIV.RDB$USER_TYPE = user_type AND
|
|
PRIV.RDB$FIELD_NAME EQ field
|
|
if (!DYN_REQUEST(drq_e_grant1))
|
|
DYN_REQUEST(drq_e_grant1) = request;
|
|
|
|
DYN_terminate(PRIV.RDB$GRANTOR, sizeof(PRIV.RDB$GRANTOR));
|
|
if ((revoking_user->usr_flags & USR_locksmith) ||
|
|
(!strcmp(PRIV.RDB$GRANTOR, revoking_user_name)))
|
|
{
|
|
ERASE PRIV;
|
|
grant_erased = TRUE;
|
|
};
|
|
|
|
END_FOR;
|
|
if (!DYN_REQUEST(drq_e_grant1)) {
|
|
DYN_REQUEST(drq_e_grant1) = request;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
FOR(REQUEST_HANDLE request TRANSACTION_HANDLE gbl->gbl_transaction)
|
|
PRIV IN RDB$USER_PRIVILEGES WITH
|
|
PRIV.RDB$PRIVILEGE EQ temp AND
|
|
PRIV.RDB$RELATION_NAME EQ object AND
|
|
PRIV.RDB$OBJECT_TYPE = obj_type AND
|
|
PRIV.RDB$USER EQ user AND
|
|
PRIV.RDB$USER_TYPE = user_type
|
|
if (!DYN_REQUEST(drq_e_grant2))
|
|
DYN_REQUEST(drq_e_grant2) = request;
|
|
|
|
DYN_terminate(PRIV.RDB$GRANTOR, sizeof(PRIV.RDB$GRANTOR));
|
|
|
|
/* revoking a permission at the table level implies
|
|
revoking the perm. on all columns. So for all fields
|
|
in this table which have been granted the privilege, we
|
|
erase the entries from RDB$USER_PRIVILEGES. */
|
|
|
|
if ((revoking_user->usr_flags & USR_locksmith) ||
|
|
(!strcmp(PRIV.RDB$GRANTOR, revoking_user_name))) {
|
|
ERASE PRIV;
|
|
grant_erased = TRUE;
|
|
}
|
|
END_FOR;
|
|
if (!DYN_REQUEST(drq_e_grant2))
|
|
DYN_REQUEST(drq_e_grant2) = request;
|
|
}
|
|
|
|
if (options && grant_erased) {
|
|
/* Add the privilege without the grant option
|
|
* There is a modify trigger on the rdb$user_privileges
|
|
* which disallows the table from being updated. It would
|
|
* have to be changed such that only the grant_option
|
|
* field can be updated.
|
|
*/
|
|
|
|
old_id = id;
|
|
id = drq_s_grant;
|
|
|
|
store_privilege(gbl, object, user, field, p, user_type, obj_type,
|
|
0);
|
|
|
|
id = old_id;
|
|
}
|
|
}
|
|
|
|
}
|
|
catch (...) {
|
|
/* we need to rundown as we have to set the env.
|
|
But in case the error is from store_priveledge we have already
|
|
unwound the request so passing that as null */
|
|
DYN_rundown_request(((id == drq_s_grant) ? NULL : request),
|
|
-1);
|
|
if (id == drq_e_grant1)
|
|
{
|
|
DYN_error_punt(TRUE, 111, NULL, NULL, NULL, NULL, NULL);
|
|
/* msg 111: "ERASE RDB$USER_PRIVILEGES failed in revoke(1)" */
|
|
}
|
|
else if (id == drq_e_grant2)
|
|
{
|
|
DYN_error_punt(TRUE, 113, NULL, NULL, NULL, NULL, NULL);
|
|
/* msg 113: "ERASE RDB$USER_PRIVILEGES failed in revoke (3)" */
|
|
}
|
|
else
|
|
{
|
|
ERR_punt();
|
|
/* store_priviledge error already handled, just bail out */
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
static void set_field_class_name(GBL gbl, TEXT * relation, TEXT * field)
|
|
{
|
|
/**************************************
|
|
*
|
|
* s e t _ f i e l d _ c l a s s _ n a m e
|
|
*
|
|
**************************************
|
|
*
|
|
* Functional description
|
|
* For field level grants, be sure the
|
|
* field has a unique class name.
|
|
*
|
|
**************************************/
|
|
BLK request, request2 = NULL;
|
|
BOOLEAN unique = FALSE;
|
|
TDBB tdbb;
|
|
DBB dbb;
|
|
|
|
|
|
tdbb = GET_THREAD_DATA;
|
|
dbb = tdbb->tdbb_database;
|
|
|
|
|
|
request = (BLK) CMP_find_request(tdbb, drq_s_f_class, DYN_REQUESTS);
|
|
|
|
FOR (REQUEST_HANDLE request TRANSACTION_HANDLE gbl->gbl_transaction)
|
|
RFR IN RDB$RELATION_FIELDS
|
|
WITH RFR.RDB$FIELD_NAME = field AND
|
|
RFR.RDB$RELATION_NAME = relation AND
|
|
RFR.RDB$SECURITY_CLASS MISSING
|
|
|
|
MODIFY RFR
|
|
while (!unique)
|
|
{
|
|
sprintf(RFR.RDB$SECURITY_CLASS, "%s%" QUADFORMAT "d\0", "SQL$GRANT",
|
|
DPM_gen_id(tdbb,
|
|
MET_lookup_generator(tdbb, "RDB$SECURITY_CLASS"), 0, (SINT64) 1));
|
|
|
|
unique = TRUE;
|
|
request2 = (BLK) CMP_find_request(tdbb, drq_s_u_class, DYN_REQUESTS);
|
|
FOR (REQUEST_HANDLE request2 TRANSACTION_HANDLE gbl->gbl_transaction)
|
|
RFR1 IN RDB$RELATION_FIELDS
|
|
WITH RFR1.RDB$SECURITY_CLASS = RFR.RDB$SECURITY_CLASS
|
|
unique = FALSE;
|
|
END_FOR;
|
|
}
|
|
|
|
RFR.RDB$SECURITY_CLASS.NULL = FALSE;
|
|
END_MODIFY;
|
|
|
|
END_FOR;
|
|
|
|
if (!DYN_REQUEST(drq_s_f_class))
|
|
DYN_REQUEST(drq_s_f_class) = request;
|
|
|
|
|
|
if (request2 && !DYN_REQUEST(drq_s_u_class))
|
|
DYN_REQUEST(drq_s_u_class) = request2;
|
|
}
|
|
|
|
|
|
static void store_privilege(GBL gbl,
|
|
TEXT* object,
|
|
TEXT* user,
|
|
TEXT* field,
|
|
TEXT* privilege,
|
|
SSHORT user_type,
|
|
SSHORT obj_type,
|
|
int option)
|
|
{
|
|
/**************************************
|
|
*
|
|
* s t o r e _ p r i v i l e g e
|
|
*
|
|
**************************************
|
|
*
|
|
* Functional description
|
|
* Does its own cleanup in case of error, so calling
|
|
* routine should not.
|
|
*
|
|
**************************************/
|
|
TDBB tdbb;
|
|
DBB dbb;
|
|
BLK request;
|
|
|
|
tdbb = GET_THREAD_DATA;
|
|
dbb = tdbb->tdbb_database;
|
|
|
|
request = (BLK) CMP_find_request(tdbb, drq_s_grant, DYN_REQUESTS);
|
|
|
|
/* need to unwind our own request here!! SM 27-Sep-96 */
|
|
|
|
try {
|
|
STORE(REQUEST_HANDLE request TRANSACTION_HANDLE gbl->gbl_transaction)
|
|
PRIV IN RDB$USER_PRIVILEGES PRIV.RDB$FIELD_NAME.NULL = TRUE;
|
|
strcpy(PRIV.RDB$RELATION_NAME, object);
|
|
strcpy(PRIV.RDB$USER, user);
|
|
PRIV.RDB$USER_TYPE = user_type;
|
|
PRIV.RDB$OBJECT_TYPE = obj_type;
|
|
if (field && field[0]) {
|
|
strcpy(PRIV.RDB$FIELD_NAME, field);
|
|
PRIV.RDB$FIELD_NAME.NULL = FALSE;
|
|
set_field_class_name(gbl, object, field);
|
|
}
|
|
PRIV.RDB$PRIVILEGE[0] = privilege[0];
|
|
PRIV.RDB$PRIVILEGE[1] = 0;
|
|
PRIV.RDB$GRANT_OPTION = option;
|
|
|
|
END_STORE;
|
|
|
|
if (!DYN_REQUEST(drq_s_grant)) {
|
|
DYN_REQUEST(drq_s_grant) = request;
|
|
}
|
|
}
|
|
catch (...) {
|
|
DYN_rundown_request(request, -1);
|
|
DYN_error_punt(TRUE, 79, NULL, NULL, NULL, NULL, NULL);
|
|
/* msg 79: "STORE RDB$USER_PRIVILEGES failed in grant" */
|
|
}
|
|
}
|