2001-05-23 15:26:42 +02:00
|
|
|
/*
|
|
|
|
* PROGRAM: JRD Access Method
|
2003-10-29 11:53:47 +01:00
|
|
|
* MODULE: grant.epp
|
2001-05-23 15:26:42 +02:00
|
|
|
* DESCRIPTION: SQL Grant/Revoke Handler
|
|
|
|
*
|
|
|
|
* 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): ______________________________________.
|
2002-10-30 07:40:58 +01:00
|
|
|
*
|
|
|
|
* 2002.10.29 Sean Leyne - Removed obsolete "Netware" port
|
|
|
|
*
|
2001-05-23 15:26:42 +02:00
|
|
|
*/
|
|
|
|
|
2001-07-29 19:42:23 +02:00
|
|
|
#include "firebird.h"
|
2001-05-23 15:26:42 +02:00
|
|
|
#include <stdio.h>
|
|
|
|
#include <string.h>
|
2004-03-22 12:38:23 +01:00
|
|
|
#include "../jrd/common.h"
|
2003-11-08 17:40:17 +01:00
|
|
|
#include "../jrd/ibase.h"
|
2001-05-23 15:26:42 +02:00
|
|
|
#include "../jrd/jrd.h"
|
|
|
|
#include "../jrd/scl.h"
|
|
|
|
#include "../jrd/acl.h"
|
|
|
|
#include "../jrd/irq.h"
|
|
|
|
#include "../jrd/blb.h"
|
2003-11-30 22:04:18 +01:00
|
|
|
#include "../jrd/btr.h"
|
2001-05-23 15:26:42 +02:00
|
|
|
#include "../jrd/req.h"
|
|
|
|
#include "../jrd/tra.h"
|
|
|
|
#include "../jrd/val.h"
|
|
|
|
#include "../jrd/met.h"
|
|
|
|
#include "../jrd/intl.h"
|
|
|
|
#include "../jrd/blb_proto.h"
|
|
|
|
#include "../jrd/cmp_proto.h"
|
|
|
|
#include "../jrd/dfw_proto.h"
|
|
|
|
#include "../jrd/dpm_proto.h"
|
2002-07-05 17:00:26 +02:00
|
|
|
#include "../jrd/dyn_proto.h"
|
2001-05-23 15:26:42 +02:00
|
|
|
#include "../jrd/err_proto.h"
|
|
|
|
#include "../jrd/exe_proto.h"
|
|
|
|
#include "../jrd/gds_proto.h"
|
|
|
|
#include "../jrd/grant_proto.h"
|
|
|
|
#include "../jrd/jrd_proto.h"
|
|
|
|
#include "../jrd/met_proto.h"
|
|
|
|
#include "../jrd/scl_proto.h"
|
2003-12-31 06:36:12 +01:00
|
|
|
#include "../common/utils_proto.h"
|
2006-07-31 17:43:20 +02:00
|
|
|
#include "../common/classes/array.h"
|
2001-05-23 15:26:42 +02:00
|
|
|
|
2004-03-20 15:57:40 +01:00
|
|
|
using namespace Jrd;
|
|
|
|
|
2001-05-23 15:26:42 +02:00
|
|
|
/* privileges given to the owner of a relation */
|
|
|
|
|
2004-07-06 07:59:40 +02:00
|
|
|
const SecurityClass::flags_t OWNER_PRIVS = SCL_control | SCL_read | SCL_write | SCL_delete | SCL_protect;
|
|
|
|
const SecurityClass::flags_t VIEW_PRIVS = SCL_read | SCL_write | SCL_delete;
|
2004-05-07 12:48:06 +02:00
|
|
|
const ULONG ACL_BUFFER_SIZE = 4096;
|
|
|
|
static const char* DEFAULT_CLASS = "SQL$DEFAULT";
|
2001-05-23 15:26:42 +02:00
|
|
|
|
2008-07-11 15:50:59 +02:00
|
|
|
inline void CHECK_AND_MOVE(Acl& to, UCHAR from)
|
|
|
|
{
|
|
|
|
to.add(from);
|
|
|
|
}
|
2001-05-23 15:26:42 +02:00
|
|
|
|
|
|
|
DATABASE DB = STATIC "yachts.lnk";
|
|
|
|
|
2008-07-11 15:50:59 +02:00
|
|
|
static void define_default_class(thread_db*, const TEXT*, Firebird::MetaName&, const Acl&);
|
2003-03-03 10:22:32 +01:00
|
|
|
#ifdef NOT_USED_OR_REPLACED
|
2004-07-06 07:59:40 +02:00
|
|
|
static void delete_security_class(thread_db*, const TEXT*);
|
2003-03-03 10:22:32 +01:00
|
|
|
#endif
|
2008-07-11 15:50:59 +02:00
|
|
|
static void finish_security_class(Acl&, SecurityClass::flags_t);
|
2004-03-11 06:04:26 +01:00
|
|
|
static void get_object_info(thread_db*, const TEXT*, SSHORT,
|
2005-05-12 20:28:04 +02:00
|
|
|
Firebird::MetaName&, Firebird::MetaName&, Firebird::MetaName&, bool&);
|
2004-07-06 07:59:40 +02:00
|
|
|
static SecurityClass::flags_t get_public_privs(thread_db*, const TEXT*, SSHORT);
|
2008-07-11 15:50:59 +02:00
|
|
|
static void get_user_privs(thread_db*, Acl&, const TEXT*, SSHORT, const Firebird::MetaName&,
|
|
|
|
SecurityClass::flags_t);
|
|
|
|
static void grant_user(Acl&, const Firebird::MetaName&, SSHORT, SecurityClass::flags_t);
|
2003-03-03 10:22:32 +01:00
|
|
|
#ifdef NOT_USED_OR_REPLACED
|
2008-07-11 15:50:59 +02:00
|
|
|
static void grant_views(TEXT**, SecurityClass::flags_t);
|
2004-05-06 10:42:15 +02:00
|
|
|
static void purge_default_class(TEXT*, SSHORT);
|
2003-03-03 10:22:32 +01:00
|
|
|
#endif
|
2008-07-11 15:50:59 +02:00
|
|
|
static SecurityClass::flags_t save_field_privileges(thread_db*, Acl&,
|
2005-05-12 20:28:04 +02:00
|
|
|
const TEXT*, const Firebird::MetaName&,
|
2008-07-11 15:50:59 +02:00
|
|
|
SecurityClass::flags_t);
|
|
|
|
static void save_security_class(thread_db*, const Firebird::MetaName&, const Acl&);
|
2004-07-06 07:59:40 +02:00
|
|
|
static SecurityClass::flags_t trans_sql_priv(const TEXT*);
|
2008-07-11 15:50:59 +02:00
|
|
|
static SecurityClass::flags_t squeeze_acl(Acl&, const Firebird::MetaName&, SSHORT);
|
2005-05-12 20:28:04 +02:00
|
|
|
static bool check_string(const UCHAR*, const Firebird::MetaName&);
|
2001-05-23 15:26:42 +02:00
|
|
|
|
|
|
|
|
2004-03-18 06:56:06 +01:00
|
|
|
bool GRANT_privileges( thread_db* tdbb, SSHORT phase, DeferredWork* work,
|
2003-12-31 06:36:12 +01:00
|
|
|
jrd_tra*) // unused param, makes dfw.epp happy
|
2001-05-23 15:26:42 +02:00
|
|
|
{
|
|
|
|
/**************************************
|
|
|
|
*
|
|
|
|
* G R A N T _ p r i v i l e g e s
|
|
|
|
*
|
|
|
|
**************************************
|
|
|
|
*
|
|
|
|
* Functional description
|
|
|
|
* Compute access control list from SQL privileges.
|
|
|
|
* This calculation is tricky and involves interaction between
|
|
|
|
* the relation-level and field-level privileges. Do not change
|
|
|
|
* the order of operations lightly.
|
|
|
|
*
|
|
|
|
**************************************/
|
|
|
|
switch (phase) {
|
|
|
|
case 1:
|
|
|
|
case 2:
|
2003-12-31 06:36:12 +01:00
|
|
|
return true;
|
2001-05-23 15:26:42 +02:00
|
|
|
|
|
|
|
case 3:
|
|
|
|
{
|
|
|
|
SET_TDBB(tdbb);
|
|
|
|
|
2003-12-31 06:36:12 +01:00
|
|
|
bool restrct = false;
|
2001-05-23 15:26:42 +02:00
|
|
|
|
2007-12-03 16:46:39 +01:00
|
|
|
Database* dbb = tdbb->getDatabase();
|
2005-05-12 20:28:04 +02:00
|
|
|
Firebird::MetaName s_class, owner, default_class;
|
2003-12-31 06:36:12 +01:00
|
|
|
bool view; // unused after being retrieved.
|
2005-05-12 20:28:04 +02:00
|
|
|
get_object_info(tdbb, work->dfw_name.c_str(), work->dfw_id, owner,
|
|
|
|
s_class, default_class, view);
|
2001-05-23 15:26:42 +02:00
|
|
|
|
2005-05-12 20:28:04 +02:00
|
|
|
if (s_class.length() == 0) {
|
2003-12-31 06:36:12 +01:00
|
|
|
return false;
|
2001-05-23 15:26:42 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
/* start the acl off by giving the owner all privileges */
|
2008-07-11 15:50:59 +02:00
|
|
|
Acl acl, default_acl;
|
2001-05-23 15:26:42 +02:00
|
|
|
|
2008-07-11 15:50:59 +02:00
|
|
|
CHECK_AND_MOVE(acl, ACL_version);
|
|
|
|
grant_user(acl, owner, obj_user,
|
|
|
|
((work->dfw_id == obj_procedure) ? (SCL_execute | OWNER_PRIVS) : OWNER_PRIVS));
|
2001-05-23 15:26:42 +02:00
|
|
|
|
|
|
|
/* Pick up any relation-level privileges */
|
|
|
|
|
2004-07-06 07:59:40 +02:00
|
|
|
const SecurityClass::flags_t public_priv =
|
2005-05-12 20:28:04 +02:00
|
|
|
get_public_privs(tdbb, work->dfw_name.c_str(), work->dfw_id);
|
2008-07-11 15:50:59 +02:00
|
|
|
get_user_privs(tdbb, acl, work->dfw_name.c_str(), work->dfw_id, owner, public_priv);
|
2001-05-23 15:26:42 +02:00
|
|
|
|
2001-12-24 03:51:06 +01:00
|
|
|
if (work->dfw_id == obj_relation)
|
|
|
|
{
|
2001-05-23 15:26:42 +02:00
|
|
|
/* Now handle field-level privileges. This might require adding
|
|
|
|
UPDATE privilege to the relation-level acl, Therefore, save
|
|
|
|
off the relation acl because we need to add a default field
|
|
|
|
acl in that case. */
|
|
|
|
|
2008-07-11 15:50:59 +02:00
|
|
|
default_acl.assign(acl);
|
2001-05-23 15:26:42 +02:00
|
|
|
|
2004-07-06 07:59:40 +02:00
|
|
|
const SecurityClass::flags_t aggregate_public =
|
2008-07-11 15:50:59 +02:00
|
|
|
save_field_privileges(tdbb, acl, work->dfw_name.c_str(), owner, public_priv);
|
2001-05-23 15:26:42 +02:00
|
|
|
|
|
|
|
/* SQL tables don't need the 'all priviliges to all views' acl anymore.
|
|
|
|
This special acl was only generated for SQL. */
|
2003-03-03 10:22:32 +01:00
|
|
|
#ifdef NOT_USED_OR_REPLACED
|
2001-05-23 15:26:42 +02:00
|
|
|
/* grant_views (&acl, VIEW_PRIVS); */
|
2003-03-03 10:22:32 +01:00
|
|
|
#endif
|
2001-05-23 15:26:42 +02:00
|
|
|
|
|
|
|
/* finish off and store the security class for the relation */
|
|
|
|
|
2008-07-11 15:50:59 +02:00
|
|
|
finish_security_class(acl, aggregate_public);
|
2001-05-23 15:26:42 +02:00
|
|
|
|
2008-07-11 15:50:59 +02:00
|
|
|
save_security_class(tdbb, s_class, acl);
|
2001-05-23 15:26:42 +02:00
|
|
|
|
2008-07-11 15:50:59 +02:00
|
|
|
if (acl.getCount() != default_acl.getCount()) /* relation privs were added? */
|
2003-12-31 06:36:12 +01:00
|
|
|
restrct = true;
|
2001-05-23 15:26:42 +02:00
|
|
|
|
|
|
|
/* if there have been privileges added at the relation level which
|
|
|
|
need to be restricted from other fields in the relation,
|
|
|
|
update the acl for them */
|
|
|
|
|
|
|
|
if (restrct)
|
|
|
|
{
|
2008-07-11 15:50:59 +02:00
|
|
|
finish_security_class(default_acl, public_priv);
|
|
|
|
define_default_class(tdbb, work->dfw_name.c_str(), default_class, default_acl);
|
2001-05-23 15:26:42 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
else {
|
2008-07-11 15:50:59 +02:00
|
|
|
finish_security_class(acl, public_priv);
|
|
|
|
save_security_class(tdbb, s_class, acl);
|
2001-05-23 15:26:42 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
default:
|
2008-03-18 14:04:05 +01:00
|
|
|
SET_TDBB(tdbb);
|
2001-05-23 15:26:42 +02:00
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
2008-03-18 14:04:05 +01:00
|
|
|
DFW_perform_system_work(tdbb);
|
2001-05-23 15:26:42 +02:00
|
|
|
|
2003-12-31 06:36:12 +01:00
|
|
|
return false;
|
2001-05-23 15:26:42 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
static void define_default_class(
|
2004-03-11 06:04:26 +01:00
|
|
|
thread_db* tdbb,
|
2003-12-31 06:36:12 +01:00
|
|
|
const TEXT* relation_name,
|
2005-05-12 20:28:04 +02:00
|
|
|
Firebird::MetaName& default_class,
|
2008-07-11 15:50:59 +02:00
|
|
|
const Acl& acl)
|
2001-05-23 15:26:42 +02:00
|
|
|
{
|
|
|
|
/**************************************
|
|
|
|
*
|
|
|
|
* d e f i n e _ d e f a u l t _ c l a s s
|
|
|
|
*
|
|
|
|
**************************************
|
|
|
|
*
|
|
|
|
* Functional description
|
|
|
|
* Update the default security class for fields
|
|
|
|
* which have not been specifically granted
|
|
|
|
* any privileges. We must grant them all
|
|
|
|
* privileges which were specifically granted
|
|
|
|
* at the relation level, but none of the
|
|
|
|
* privileges we added at the relation level
|
|
|
|
* for the purpose of accessing other fields.
|
|
|
|
*
|
|
|
|
**************************************/
|
|
|
|
SET_TDBB(tdbb);
|
2007-12-03 16:46:39 +01:00
|
|
|
Database* dbb = tdbb->getDatabase();
|
2001-05-23 15:26:42 +02:00
|
|
|
|
2005-05-12 20:28:04 +02:00
|
|
|
if (default_class.length() == 0) {
|
2006-05-04 02:02:58 +02:00
|
|
|
default_class.printf("%s%" SQUADFORMAT, DEFAULT_CLASS,
|
2004-07-07 05:47:12 +02:00
|
|
|
DPM_gen_id(tdbb, MET_lookup_generator(tdbb, DEFAULT_CLASS), false,
|
2001-05-23 15:26:42 +02:00
|
|
|
(SINT64) 1));
|
|
|
|
|
2004-03-20 15:57:40 +01:00
|
|
|
jrd_req* request = CMP_find_request(tdbb, irq_grant7, IRQ_REQUESTS);
|
2001-05-23 15:26:42 +02:00
|
|
|
|
|
|
|
FOR(REQUEST_HANDLE request)
|
|
|
|
REL IN RDB$RELATIONS
|
|
|
|
WITH REL.RDB$RELATION_NAME EQ relation_name
|
|
|
|
|
2003-12-31 06:36:12 +01:00
|
|
|
if (!REQUEST(irq_grant7))
|
|
|
|
REQUEST(irq_grant7) = request;
|
2001-05-23 15:26:42 +02:00
|
|
|
|
|
|
|
MODIFY REL USING
|
|
|
|
REL.RDB$DEFAULT_CLASS.NULL = FALSE;
|
2005-05-12 20:28:04 +02:00
|
|
|
jrd_vtof(default_class.c_str(), REL.RDB$DEFAULT_CLASS,
|
2001-05-23 15:26:42 +02:00
|
|
|
sizeof(REL.RDB$DEFAULT_CLASS));
|
|
|
|
END_MODIFY;
|
|
|
|
|
|
|
|
END_FOR;
|
|
|
|
|
|
|
|
if (!REQUEST(irq_grant7))
|
|
|
|
REQUEST(irq_grant7) = request;
|
|
|
|
}
|
|
|
|
|
2008-07-11 15:50:59 +02:00
|
|
|
save_security_class(tdbb, default_class, acl);
|
2001-05-23 15:26:42 +02:00
|
|
|
|
2003-12-31 06:36:12 +01:00
|
|
|
dsc desc;
|
2001-05-23 15:26:42 +02:00
|
|
|
desc.dsc_dtype = dtype_text;
|
|
|
|
desc.dsc_sub_type = 0;
|
|
|
|
desc.dsc_scale = 0;
|
2004-05-21 08:16:17 +02:00
|
|
|
desc.dsc_ttype() = ttype_metadata;
|
2001-05-23 15:26:42 +02:00
|
|
|
desc.dsc_address = (UCHAR *) relation_name;
|
2004-12-23 03:59:57 +01:00
|
|
|
desc.dsc_length = strlen(relation_name);
|
2008-06-27 10:44:40 +02:00
|
|
|
DFW_post_system_work(tdbb, dfw_scan_relation, &desc, 0);
|
2001-05-23 15:26:42 +02:00
|
|
|
}
|
|
|
|
|
2004-08-26 13:07:57 +02:00
|
|
|
|
2003-03-03 10:22:32 +01:00
|
|
|
#ifdef NOT_USED_OR_REPLACED
|
2004-07-06 07:59:40 +02:00
|
|
|
static void delete_security_class( thread_db* tdbb, const TEXT* s_class)
|
2001-05-23 15:26:42 +02:00
|
|
|
{
|
|
|
|
/**************************************
|
|
|
|
*
|
|
|
|
* d e l e t e _ s e c u r i t y _ c l a s s
|
|
|
|
*
|
|
|
|
**************************************
|
|
|
|
*
|
|
|
|
* Functional description
|
|
|
|
* Delete a security class.
|
|
|
|
*
|
|
|
|
**************************************/
|
|
|
|
SET_TDBB(tdbb);
|
2007-12-03 16:46:39 +01:00
|
|
|
Database* dbb = tdbb->getDatabase();
|
2001-05-23 15:26:42 +02:00
|
|
|
|
2004-03-20 15:57:40 +01:00
|
|
|
jrd_req* handle = NULL;
|
2001-05-23 15:26:42 +02:00
|
|
|
|
|
|
|
FOR(REQUEST_HANDLE handle)
|
|
|
|
CLS IN RDB$SECURITY_CLASSES
|
|
|
|
WITH CLS.RDB$SECURITY_CLASS EQ s_class
|
|
|
|
ERASE CLS;
|
|
|
|
END_FOR;
|
|
|
|
|
2004-08-26 13:07:57 +02:00
|
|
|
CMP_release(tdbb, handle);
|
2001-05-23 15:26:42 +02:00
|
|
|
}
|
2003-03-03 10:22:32 +01:00
|
|
|
#endif // NOT_USED_OR_REPLACED
|
2001-05-23 15:26:42 +02:00
|
|
|
|
2004-08-26 13:07:57 +02:00
|
|
|
|
2008-07-11 15:50:59 +02:00
|
|
|
static void finish_security_class(Acl& acl, SecurityClass::flags_t public_priv)
|
2001-05-23 15:26:42 +02:00
|
|
|
{
|
|
|
|
/**************************************
|
|
|
|
*
|
|
|
|
* f i n i s h _ s e c u r i t y _ c l a s s
|
|
|
|
*
|
|
|
|
**************************************
|
|
|
|
*
|
|
|
|
* Functional description
|
|
|
|
* Finish off a security class, putting
|
|
|
|
* in a wildcard for any public privileges.
|
|
|
|
*
|
|
|
|
**************************************/
|
2001-07-12 08:32:05 +02:00
|
|
|
if (public_priv) {
|
2008-07-11 15:50:59 +02:00
|
|
|
CHECK_AND_MOVE(acl, ACL_id_list);
|
|
|
|
SCL_move_priv(public_priv, acl);
|
2001-05-23 15:26:42 +02:00
|
|
|
}
|
|
|
|
|
2008-07-11 15:50:59 +02:00
|
|
|
CHECK_AND_MOVE(acl, ACL_end);
|
2001-05-23 15:26:42 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2004-07-06 07:59:40 +02:00
|
|
|
static SecurityClass::flags_t get_public_privs(
|
|
|
|
thread_db* tdbb,
|
|
|
|
const TEXT* object_name,
|
|
|
|
SSHORT obj_type)
|
2001-05-23 15:26:42 +02:00
|
|
|
{
|
|
|
|
/**************************************
|
|
|
|
*
|
|
|
|
* g e t _ p u b l i c _ p r i v s
|
|
|
|
*
|
|
|
|
**************************************
|
|
|
|
*
|
|
|
|
* Functional description
|
|
|
|
* Get public privileges for a particular object.
|
|
|
|
*
|
|
|
|
**************************************/
|
|
|
|
SET_TDBB(tdbb);
|
2007-12-03 16:46:39 +01:00
|
|
|
Database* dbb = tdbb->getDatabase();
|
2001-05-23 15:26:42 +02:00
|
|
|
|
2004-07-06 07:59:40 +02:00
|
|
|
SecurityClass::flags_t public_priv = 0;
|
2001-05-23 15:26:42 +02:00
|
|
|
|
2004-03-20 15:57:40 +01:00
|
|
|
jrd_req* request = CMP_find_request(tdbb, irq_grant5, IRQ_REQUESTS);
|
2001-05-23 15:26:42 +02:00
|
|
|
|
|
|
|
FOR(REQUEST_HANDLE request)
|
|
|
|
PRV IN RDB$USER_PRIVILEGES
|
|
|
|
WITH PRV.RDB$RELATION_NAME EQ object_name AND
|
|
|
|
PRV.RDB$OBJECT_TYPE EQ obj_type AND
|
|
|
|
PRV.RDB$USER EQ "PUBLIC" AND
|
|
|
|
PRV.RDB$USER_TYPE EQ obj_user AND
|
|
|
|
PRV.RDB$FIELD_NAME MISSING
|
|
|
|
if (!REQUEST(irq_grant5))
|
|
|
|
REQUEST(irq_grant5) = request;
|
2001-07-12 08:32:05 +02:00
|
|
|
public_priv |= trans_sql_priv(PRV.RDB$PRIVILEGE);
|
2001-05-23 15:26:42 +02:00
|
|
|
END_FOR;
|
|
|
|
|
|
|
|
if (!REQUEST(irq_grant5))
|
|
|
|
REQUEST(irq_grant5) = request;
|
|
|
|
|
2001-07-12 08:32:05 +02:00
|
|
|
return public_priv;
|
2001-05-23 15:26:42 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2005-05-12 20:28:04 +02:00
|
|
|
static void get_object_info(thread_db* tdbb,
|
2003-12-31 06:36:12 +01:00
|
|
|
const TEXT* object_name,
|
2001-05-23 15:26:42 +02:00
|
|
|
SSHORT obj_type,
|
2005-05-12 20:28:04 +02:00
|
|
|
Firebird::MetaName& owner,
|
|
|
|
Firebird::MetaName& s_class,
|
|
|
|
Firebird::MetaName& default_class,
|
|
|
|
bool& view)
|
2001-05-23 15:26:42 +02:00
|
|
|
{
|
|
|
|
/**************************************
|
|
|
|
*
|
|
|
|
* g e t _ o b j e c t _ i n f o
|
|
|
|
*
|
|
|
|
**************************************
|
|
|
|
*
|
|
|
|
* Functional description
|
|
|
|
* This could be done in MET_scan_relation () or MET_lookup_procedure,
|
|
|
|
* but presumably we wish to make sure the information we have is
|
|
|
|
* up-to-the-minute.
|
|
|
|
*
|
|
|
|
**************************************/
|
|
|
|
SET_TDBB(tdbb);
|
2007-12-03 16:46:39 +01:00
|
|
|
Database* dbb = tdbb->getDatabase();
|
2001-05-23 15:26:42 +02:00
|
|
|
|
2005-05-12 20:28:04 +02:00
|
|
|
owner = s_class = default_class = "";
|
|
|
|
view = false;
|
2001-05-23 15:26:42 +02:00
|
|
|
|
|
|
|
if (obj_type == obj_relation) {
|
2004-03-20 15:57:40 +01:00
|
|
|
jrd_req* request = CMP_find_request(tdbb, irq_grant1, IRQ_REQUESTS);
|
2001-05-23 15:26:42 +02:00
|
|
|
|
|
|
|
FOR(REQUEST_HANDLE request)
|
|
|
|
REL IN RDB$RELATIONS WITH
|
|
|
|
REL.RDB$RELATION_NAME EQ object_name
|
|
|
|
|
|
|
|
if (!REQUEST(irq_grant1))
|
|
|
|
REQUEST(irq_grant1) = request;
|
2004-12-23 03:59:57 +01:00
|
|
|
|
2005-05-12 20:28:04 +02:00
|
|
|
s_class = REL.RDB$SECURITY_CLASS;
|
|
|
|
default_class = REL.RDB$DEFAULT_CLASS;
|
|
|
|
owner = REL.RDB$OWNER_NAME;
|
|
|
|
view = !REL.RDB$VIEW_BLR.isEmpty();
|
2001-05-23 15:26:42 +02:00
|
|
|
END_FOR;
|
|
|
|
|
|
|
|
if (!REQUEST(irq_grant1))
|
|
|
|
REQUEST(irq_grant1) = request;
|
|
|
|
}
|
|
|
|
else {
|
2004-03-20 15:57:40 +01:00
|
|
|
jrd_req* request = CMP_find_request(tdbb, irq_grant9, IRQ_REQUESTS);
|
2001-05-23 15:26:42 +02:00
|
|
|
|
|
|
|
FOR(REQUEST_HANDLE request)
|
|
|
|
REL IN RDB$PROCEDURES WITH
|
|
|
|
REL.RDB$PROCEDURE_NAME EQ object_name
|
|
|
|
|
2004-12-23 03:59:57 +01:00
|
|
|
if (!REQUEST(irq_grant9))
|
|
|
|
REQUEST(irq_grant9) = request;
|
2001-05-23 15:26:42 +02:00
|
|
|
|
2005-05-12 20:28:04 +02:00
|
|
|
s_class = REL.RDB$SECURITY_CLASS;
|
|
|
|
default_class = "";
|
|
|
|
owner = REL.RDB$OWNER_NAME;
|
|
|
|
view = false;
|
2001-05-23 15:26:42 +02:00
|
|
|
END_FOR;
|
|
|
|
|
|
|
|
if (!REQUEST(irq_grant9))
|
|
|
|
REQUEST(irq_grant9) = request;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2005-05-12 20:28:04 +02:00
|
|
|
static void get_user_privs(thread_db* tdbb,
|
2008-07-11 15:50:59 +02:00
|
|
|
Acl& acl,
|
2005-05-12 20:28:04 +02:00
|
|
|
const TEXT* object_name,
|
|
|
|
SSHORT obj_type,
|
|
|
|
const Firebird::MetaName& owner,
|
2008-07-11 15:50:59 +02:00
|
|
|
SecurityClass::flags_t public_priv)
|
2001-05-23 15:26:42 +02:00
|
|
|
{
|
|
|
|
/**************************************
|
|
|
|
*
|
|
|
|
* g e t _ u s e r _ p r i v s
|
|
|
|
*
|
|
|
|
**************************************
|
|
|
|
*
|
|
|
|
* Functional description
|
|
|
|
* Get privileges for a particular object.
|
|
|
|
*
|
|
|
|
**************************************/
|
|
|
|
SET_TDBB(tdbb);
|
2007-12-03 16:46:39 +01:00
|
|
|
Database* dbb = tdbb->getDatabase();
|
2001-05-23 15:26:42 +02:00
|
|
|
|
2005-05-12 20:28:04 +02:00
|
|
|
Firebird::MetaName user;
|
2004-02-20 07:43:27 +01:00
|
|
|
SSHORT user_type = -2;
|
2004-07-06 07:59:40 +02:00
|
|
|
SecurityClass::flags_t priv = 0;
|
2001-05-23 15:26:42 +02:00
|
|
|
|
2004-03-20 15:57:40 +01:00
|
|
|
jrd_req* request = CMP_find_request(tdbb, irq_grant2, IRQ_REQUESTS);
|
2001-05-23 15:26:42 +02:00
|
|
|
|
|
|
|
FOR(REQUEST_HANDLE request)
|
|
|
|
PRV IN RDB$USER_PRIVILEGES
|
|
|
|
WITH PRV.RDB$RELATION_NAME EQ object_name AND
|
|
|
|
PRV.RDB$OBJECT_TYPE EQ obj_type AND
|
|
|
|
(PRV.RDB$USER NE "PUBLIC" OR PRV.RDB$USER_TYPE NE obj_user) AND
|
2005-05-12 20:28:04 +02:00
|
|
|
(PRV.RDB$USER NE owner.c_str() OR PRV.RDB$USER_TYPE NE obj_user) AND
|
2001-05-23 15:26:42 +02:00
|
|
|
PRV.RDB$FIELD_NAME MISSING
|
|
|
|
SORTED BY PRV.RDB$USER, PRV.RDB$USER_TYPE
|
|
|
|
|
2004-02-20 07:43:27 +01:00
|
|
|
if (!REQUEST(irq_grant2))
|
|
|
|
REQUEST(irq_grant2) = request;
|
2001-05-23 15:26:42 +02:00
|
|
|
|
2004-09-26 03:49:52 +02:00
|
|
|
fb_utils::exact_name_limit(PRV.RDB$USER, sizeof(PRV.RDB$USER));
|
2005-05-12 20:28:04 +02:00
|
|
|
if (user != PRV.RDB$USER || user_type != PRV.RDB$USER_TYPE)
|
2001-05-23 15:26:42 +02:00
|
|
|
{
|
2005-05-12 20:28:04 +02:00
|
|
|
if (user.length())
|
2001-05-23 15:26:42 +02:00
|
|
|
{
|
2008-07-11 15:50:59 +02:00
|
|
|
grant_user(acl, user, user_type, priv);
|
2001-05-23 15:26:42 +02:00
|
|
|
}
|
|
|
|
user_type = PRV.RDB$USER_TYPE;
|
|
|
|
if (user_type == obj_user)
|
|
|
|
{
|
2001-07-12 08:32:05 +02:00
|
|
|
priv = public_priv;
|
2001-05-23 15:26:42 +02:00
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
priv = 0;
|
|
|
|
}
|
2005-05-12 20:28:04 +02:00
|
|
|
user = PRV.RDB$USER;
|
2001-05-23 15:26:42 +02:00
|
|
|
}
|
|
|
|
priv |= trans_sql_priv(PRV.RDB$PRIVILEGE);
|
|
|
|
END_FOR;
|
|
|
|
|
|
|
|
if (!REQUEST(irq_grant2))
|
|
|
|
REQUEST(irq_grant2) = request;
|
|
|
|
|
2005-05-12 20:28:04 +02:00
|
|
|
if (user.length())
|
2008-07-11 15:50:59 +02:00
|
|
|
grant_user(acl, user, user_type, priv);
|
2001-05-23 15:26:42 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2008-07-11 15:50:59 +02:00
|
|
|
static void grant_user(Acl& acl,
|
2005-05-12 20:28:04 +02:00
|
|
|
const Firebird::MetaName& user,
|
|
|
|
SSHORT user_type,
|
2008-07-11 15:50:59 +02:00
|
|
|
SecurityClass::flags_t privs)
|
2001-05-23 15:26:42 +02:00
|
|
|
{
|
|
|
|
/**************************************
|
|
|
|
*
|
|
|
|
* g r a n t _ u s e r
|
|
|
|
*
|
|
|
|
**************************************
|
|
|
|
*
|
|
|
|
* Functional description
|
|
|
|
* Grant privileges to a particular user.
|
|
|
|
*
|
|
|
|
**************************************/
|
2008-07-11 15:50:59 +02:00
|
|
|
CHECK_AND_MOVE(acl, ACL_id_list);
|
2001-05-23 15:26:42 +02:00
|
|
|
switch (user_type) {
|
|
|
|
case obj_user_group:
|
2008-07-11 15:50:59 +02:00
|
|
|
CHECK_AND_MOVE(acl, id_group);
|
2001-05-23 15:26:42 +02:00
|
|
|
break;
|
|
|
|
|
|
|
|
case obj_sql_role:
|
2008-07-11 15:50:59 +02:00
|
|
|
CHECK_AND_MOVE(acl, id_sql_role);
|
2001-05-23 15:26:42 +02:00
|
|
|
break;
|
|
|
|
|
|
|
|
case obj_user:
|
2008-07-11 15:50:59 +02:00
|
|
|
CHECK_AND_MOVE(acl, id_person);
|
2001-05-23 15:26:42 +02:00
|
|
|
break;
|
|
|
|
|
|
|
|
case obj_procedure:
|
2008-07-11 15:50:59 +02:00
|
|
|
CHECK_AND_MOVE(acl, id_procedure);
|
2001-05-23 15:26:42 +02:00
|
|
|
break;
|
|
|
|
|
|
|
|
case obj_trigger:
|
2008-07-11 15:50:59 +02:00
|
|
|
CHECK_AND_MOVE(acl, id_trigger);
|
2001-05-23 15:26:42 +02:00
|
|
|
break;
|
|
|
|
|
|
|
|
case obj_view:
|
2008-07-11 15:50:59 +02:00
|
|
|
CHECK_AND_MOVE(acl, id_view);
|
2001-05-23 15:26:42 +02:00
|
|
|
break;
|
|
|
|
|
|
|
|
default:
|
|
|
|
BUGCHECK(292); /* Illegal user_type */
|
|
|
|
|
|
|
|
}
|
|
|
|
|
2005-05-12 20:28:04 +02:00
|
|
|
const UCHAR length = user.length();
|
2008-07-11 15:50:59 +02:00
|
|
|
CHECK_AND_MOVE(acl, length);
|
2001-05-23 15:26:42 +02:00
|
|
|
if (length) {
|
2008-07-11 15:50:59 +02:00
|
|
|
acl.add(reinterpret_cast<const UCHAR*>(user.c_str()), length);
|
2001-05-23 15:26:42 +02:00
|
|
|
}
|
|
|
|
|
2008-07-11 15:50:59 +02:00
|
|
|
SCL_move_priv(privs, acl);
|
2001-05-23 15:26:42 +02:00
|
|
|
}
|
|
|
|
|
2003-03-03 10:22:32 +01:00
|
|
|
#ifdef NOT_USED_OR_REPLACED
|
2001-05-23 15:26:42 +02:00
|
|
|
static void grant_views(
|
2008-07-11 15:50:59 +02:00
|
|
|
Acl& acl,
|
|
|
|
SecurityClass::flags_t privs)
|
2001-05-23 15:26:42 +02:00
|
|
|
{
|
|
|
|
/**************************************
|
|
|
|
*
|
|
|
|
* g r a n t _ v i e w s
|
|
|
|
*
|
|
|
|
**************************************
|
|
|
|
*
|
|
|
|
* Functional description
|
|
|
|
* Grant privileges to all views.
|
|
|
|
*
|
|
|
|
**************************************/
|
2008-07-11 15:50:59 +02:00
|
|
|
CHECK_AND_MOVE(acl, ACL_id_list);
|
|
|
|
CHECK_AND_MOVE(acl, id_views);
|
|
|
|
CHECK_AND_MOVE(acl, 0);
|
|
|
|
SCL_move_priv(privs, acl);
|
2001-05-23 15:26:42 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2004-07-06 07:59:40 +02:00
|
|
|
static void purge_default_class( TEXT* object_name, SSHORT obj_type)
|
2001-05-23 15:26:42 +02:00
|
|
|
{
|
|
|
|
/**************************************
|
|
|
|
*
|
|
|
|
* p u r g e _ d e f a u l t _ c l a s s
|
|
|
|
*
|
|
|
|
**************************************
|
|
|
|
*
|
|
|
|
* Functional description
|
|
|
|
* Get rid of any previously defined
|
|
|
|
* default security class for this relation.
|
|
|
|
*
|
|
|
|
**************************************/
|
2004-05-22 16:28:54 +02:00
|
|
|
thread_db* tdbb = JRD_get_thread_data();
|
2007-12-03 16:46:39 +01:00
|
|
|
Database* dbb = tdbb->getDatabase();
|
2001-05-23 15:26:42 +02:00
|
|
|
|
2004-03-20 15:57:40 +01:00
|
|
|
jrd_req* request = CMP_find_request(tdbb, irq_grant8, IRQ_REQUESTS);
|
2001-05-23 15:26:42 +02:00
|
|
|
|
|
|
|
FOR(REQUEST_HANDLE request)
|
|
|
|
REL IN RDB$RELATIONS
|
|
|
|
WITH REL.RDB$RELATION_NAME EQ object_name
|
|
|
|
AND REL.RDB$DEFAULT_CLASS NOT MISSING
|
|
|
|
|
|
|
|
if (!REQUEST(irq_grant8))
|
|
|
|
REQUEST(irq_grant8) = request;
|
2004-12-23 03:59:57 +01:00
|
|
|
|
2004-09-26 03:49:52 +02:00
|
|
|
fb_utils::exact_name_limit(REL.RDB$DEFAULT_CLASS, sizeof(REL.RDB$DEFAULT_CLASS));
|
2001-05-23 15:26:42 +02:00
|
|
|
delete_security_class(tdbb, REL.RDB$DEFAULT_CLASS);
|
|
|
|
|
|
|
|
MODIFY REL USING
|
|
|
|
REL.RDB$DEFAULT_CLASS.NULL = TRUE;
|
|
|
|
END_MODIFY;
|
|
|
|
|
|
|
|
END_FOR;
|
|
|
|
|
|
|
|
if (!REQUEST(irq_grant8))
|
|
|
|
REQUEST(irq_grant8) = request;
|
|
|
|
|
2004-02-20 07:43:27 +01:00
|
|
|
dsc desc;
|
2001-05-23 15:26:42 +02:00
|
|
|
desc.dsc_dtype = dtype_text;
|
|
|
|
desc.dsc_sub_type = 0;
|
|
|
|
desc.dsc_scale = 0;
|
2004-05-21 08:16:17 +02:00
|
|
|
desc.dsc_ttype() = ttype_metadata;
|
2001-05-23 15:26:42 +02:00
|
|
|
desc.dsc_address = (UCHAR *) object_name;
|
2004-12-23 03:59:57 +01:00
|
|
|
desc.dsc_length = strlen(object_name);
|
2008-06-27 10:44:40 +02:00
|
|
|
DFW_post_system_work(tdbb, dfw_scan_relation, &desc, 0);
|
2001-05-23 15:26:42 +02:00
|
|
|
}
|
2003-03-03 10:22:32 +01:00
|
|
|
#endif // NOT_USED_OR_REPLACED
|
2001-05-23 15:26:42 +02:00
|
|
|
|
|
|
|
|
2005-05-12 20:28:04 +02:00
|
|
|
static SecurityClass::flags_t save_field_privileges(thread_db* tdbb,
|
2008-07-11 15:50:59 +02:00
|
|
|
Acl& relation_acl,
|
2005-05-12 20:28:04 +02:00
|
|
|
const TEXT* relation_name,
|
|
|
|
const Firebird::MetaName& owner,
|
2008-07-11 15:50:59 +02:00
|
|
|
SecurityClass::flags_t public_priv)
|
2001-05-23 15:26:42 +02:00
|
|
|
{
|
|
|
|
/**************************************
|
|
|
|
*
|
|
|
|
* s a v e _ f i e l d _ p r i v i l e g e s
|
|
|
|
*
|
|
|
|
**************************************
|
|
|
|
*
|
|
|
|
* Functional description
|
|
|
|
* Compute the privileges for all fields within a relation.
|
|
|
|
* All fields must be given the initial relation-level privileges.
|
|
|
|
* Conversely, field-level privileges must be added to the relation
|
|
|
|
* security class to be effective.
|
|
|
|
*
|
|
|
|
**************************************/
|
|
|
|
SET_TDBB(tdbb);
|
2007-12-03 16:46:39 +01:00
|
|
|
Database* dbb = tdbb->getDatabase();
|
2001-05-23 15:26:42 +02:00
|
|
|
|
2008-07-15 08:24:04 +02:00
|
|
|
Acl field_acl(relation_acl);
|
|
|
|
const Acl acl_start(relation_acl);
|
2001-05-23 15:26:42 +02:00
|
|
|
|
2005-05-12 20:28:04 +02:00
|
|
|
Firebird::MetaName field_name, user, s_class;
|
2004-07-06 07:59:40 +02:00
|
|
|
SecurityClass::flags_t aggregate_public = public_priv;
|
|
|
|
SecurityClass::flags_t priv, field_public;
|
|
|
|
SSHORT user_type = -1;
|
2001-05-23 15:26:42 +02:00
|
|
|
|
2004-03-20 15:57:40 +01:00
|
|
|
jrd_req* request = CMP_find_request(tdbb, irq_grant6, IRQ_REQUESTS);
|
|
|
|
jrd_req* request2 = NULL;
|
2005-10-24 13:56:00 +02:00
|
|
|
jrd_req* request3 = NULL;
|
2001-05-23 15:26:42 +02:00
|
|
|
|
|
|
|
FOR(REQUEST_HANDLE request)
|
|
|
|
FLD IN RDB$RELATION_FIELDS CROSS
|
|
|
|
PRV IN RDB$USER_PRIVILEGES
|
|
|
|
OVER RDB$RELATION_NAME, RDB$FIELD_NAME
|
|
|
|
WITH PRV.RDB$OBJECT_TYPE EQ obj_relation AND
|
|
|
|
PRV.RDB$RELATION_NAME EQ relation_name AND
|
|
|
|
PRV.RDB$FIELD_NAME NOT MISSING AND
|
2005-05-12 20:28:04 +02:00
|
|
|
(PRV.RDB$USER NE owner.c_str() OR PRV.RDB$USER_TYPE NE obj_user)
|
2001-05-23 15:26:42 +02:00
|
|
|
SORTED BY PRV.RDB$FIELD_NAME, PRV.RDB$USER
|
|
|
|
|
2005-10-24 13:56:00 +02:00
|
|
|
if (!REQUEST(irq_grant6))
|
|
|
|
REQUEST(irq_grant6) = request;
|
|
|
|
|
|
|
|
fb_utils::exact_name_limit(PRV.RDB$USER, sizeof(PRV.RDB$USER));
|
|
|
|
fb_utils::exact_name_limit(PRV.RDB$FIELD_NAME, sizeof(PRV.RDB$FIELD_NAME));
|
2001-05-23 15:26:42 +02:00
|
|
|
|
|
|
|
/* create a control break on field_name,user */
|
|
|
|
|
2005-05-12 20:28:04 +02:00
|
|
|
if (user != PRV.RDB$USER || field_name != PRV.RDB$FIELD_NAME)
|
2001-05-23 15:26:42 +02:00
|
|
|
{
|
|
|
|
/* flush out information for old user */
|
|
|
|
|
2005-05-12 20:28:04 +02:00
|
|
|
if (user.length())
|
2001-05-23 15:26:42 +02:00
|
|
|
{
|
2005-05-12 20:28:04 +02:00
|
|
|
if (user != "PUBLIC")
|
2001-05-23 15:26:42 +02:00
|
|
|
{
|
2004-07-06 07:59:40 +02:00
|
|
|
const SecurityClass::flags_t field_priv =
|
2008-07-11 15:50:59 +02:00
|
|
|
public_priv | priv | squeeze_acl(field_acl, user, user_type);
|
|
|
|
grant_user(field_acl, user, user_type, field_priv);
|
2004-07-06 07:59:40 +02:00
|
|
|
const SecurityClass::flags_t relation_priv =
|
2008-07-11 15:50:59 +02:00
|
|
|
public_priv | priv | squeeze_acl(relation_acl, user, user_type);
|
|
|
|
grant_user(relation_acl, user, user_type, relation_priv);
|
2001-05-23 15:26:42 +02:00
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
2001-07-12 08:32:05 +02:00
|
|
|
field_public = field_public | public_priv | priv;
|
2001-05-23 15:26:42 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/* initialize for new user */
|
|
|
|
|
|
|
|
priv = 0;
|
2005-05-12 20:28:04 +02:00
|
|
|
user = PRV.RDB$USER;
|
2001-05-23 15:26:42 +02:00
|
|
|
user_type = PRV.RDB$USER_TYPE;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* create a control break on field_name */
|
|
|
|
|
2005-05-12 20:28:04 +02:00
|
|
|
if (field_name != PRV.RDB$FIELD_NAME) {
|
2001-05-23 15:26:42 +02:00
|
|
|
/* finish off the last field, adding a wildcard at end, giving PUBLIC
|
|
|
|
all privileges available at the table level as well as those
|
|
|
|
granted at the field level */
|
|
|
|
|
2005-05-12 20:28:04 +02:00
|
|
|
if (field_name.length()) {
|
2001-05-23 15:26:42 +02:00
|
|
|
aggregate_public |= field_public;
|
2008-07-11 15:50:59 +02:00
|
|
|
finish_security_class(field_acl, (field_public | public_priv));
|
|
|
|
save_security_class(tdbb, s_class, field_acl);
|
2001-05-23 15:26:42 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
/* initialize for new field */
|
|
|
|
|
2005-05-12 20:28:04 +02:00
|
|
|
field_name = PRV.RDB$FIELD_NAME;
|
|
|
|
s_class = FLD.RDB$SECURITY_CLASS;
|
2005-10-28 08:18:17 +02:00
|
|
|
if (FLD.RDB$SECURITY_CLASS.NULL || s_class.length() == 0)
|
2005-10-24 13:56:00 +02:00
|
|
|
{
|
|
|
|
bool unique = false;
|
2002-07-01 17:46:07 +02:00
|
|
|
|
2001-05-23 15:26:42 +02:00
|
|
|
FOR(REQUEST_HANDLE request2)
|
2005-10-24 13:56:00 +02:00
|
|
|
RFR IN RDB$RELATION_FIELDS WITH
|
|
|
|
RFR.RDB$RELATION_NAME EQ FLD.RDB$RELATION_NAME
|
|
|
|
AND RFR.RDB$FIELD_NAME EQ FLD.RDB$FIELD_NAME
|
|
|
|
MODIFY RFR
|
|
|
|
while (!unique)
|
|
|
|
{
|
2006-05-04 02:02:58 +02:00
|
|
|
sprintf(RFR.RDB$SECURITY_CLASS, "%s%" SQUADFORMAT, "SQL$GRANT",
|
2005-10-24 13:56:00 +02:00
|
|
|
DPM_gen_id(tdbb, MET_lookup_generator(tdbb, "RDB$SECURITY_CLASS"),
|
|
|
|
false, (SINT64) 1));
|
|
|
|
|
|
|
|
unique = true;
|
|
|
|
FOR (REQUEST_HANDLE request3)
|
|
|
|
RFR2 IN RDB$RELATION_FIELDS
|
|
|
|
WITH RFR2.RDB$SECURITY_CLASS = RFR.RDB$SECURITY_CLASS
|
|
|
|
unique = false;
|
|
|
|
END_FOR;
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
RFR.RDB$SECURITY_CLASS.NULL = FALSE;
|
|
|
|
s_class = RFR.RDB$SECURITY_CLASS;
|
2001-05-23 15:26:42 +02:00
|
|
|
END_MODIFY;
|
|
|
|
END_FOR;
|
|
|
|
}
|
|
|
|
field_public = 0;
|
|
|
|
|
|
|
|
/* restart a security class at the end of the relation-level privs */
|
2008-07-11 15:50:59 +02:00
|
|
|
field_acl.assign(acl_start);
|
2001-05-23 15:26:42 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
priv |= trans_sql_priv(PRV.RDB$PRIVILEGE);
|
|
|
|
END_FOR;
|
|
|
|
|
|
|
|
if (!REQUEST(irq_grant6))
|
|
|
|
REQUEST(irq_grant6) = request;
|
|
|
|
|
|
|
|
if (request2)
|
2004-08-26 13:07:57 +02:00
|
|
|
CMP_release(tdbb, request2);
|
2001-05-23 15:26:42 +02:00
|
|
|
|
2005-10-28 09:39:30 +02:00
|
|
|
if (request3)
|
|
|
|
CMP_release(tdbb, request3);
|
|
|
|
|
2001-05-23 15:26:42 +02:00
|
|
|
/* flush out the last user's info */
|
|
|
|
|
2005-05-12 20:28:04 +02:00
|
|
|
if (user.length())
|
2001-05-23 15:26:42 +02:00
|
|
|
{
|
2005-05-12 20:28:04 +02:00
|
|
|
if (user != "PUBLIC")
|
2001-05-23 15:26:42 +02:00
|
|
|
{
|
2004-07-06 07:59:40 +02:00
|
|
|
const SecurityClass::flags_t field_priv =
|
2008-07-11 15:50:59 +02:00
|
|
|
public_priv | priv | squeeze_acl(field_acl, user, user_type);
|
|
|
|
grant_user(field_acl, user, user_type, field_priv);
|
2004-07-06 07:59:40 +02:00
|
|
|
const SecurityClass::flags_t relation_priv =
|
2008-07-11 15:50:59 +02:00
|
|
|
public_priv | priv | squeeze_acl(relation_acl, user, user_type);
|
|
|
|
grant_user(relation_acl, user, user_type, relation_priv);
|
2001-05-23 15:26:42 +02:00
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
2001-07-12 08:32:05 +02:00
|
|
|
field_public = field_public | public_priv | priv;
|
2001-05-23 15:26:42 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/* flush out the last field's info, and schedule a format update */
|
|
|
|
|
2005-05-12 20:28:04 +02:00
|
|
|
if (field_name.length())
|
2001-05-23 15:26:42 +02:00
|
|
|
{
|
|
|
|
aggregate_public |= field_public;
|
2008-07-11 15:50:59 +02:00
|
|
|
finish_security_class(field_acl, (field_public | public_priv));
|
|
|
|
save_security_class(tdbb, s_class, field_acl);
|
2004-07-06 07:59:40 +02:00
|
|
|
|
|
|
|
dsc desc;
|
2001-05-23 15:26:42 +02:00
|
|
|
desc.dsc_dtype = dtype_text;
|
|
|
|
desc.dsc_sub_type = 0;
|
|
|
|
desc.dsc_scale = 0;
|
2004-05-21 08:16:17 +02:00
|
|
|
desc.dsc_ttype() = ttype_metadata;
|
2001-05-23 15:26:42 +02:00
|
|
|
desc.dsc_address = (UCHAR *) relation_name;
|
2004-12-23 03:59:57 +01:00
|
|
|
desc.dsc_length = strlen(relation_name);
|
2008-06-27 10:44:40 +02:00
|
|
|
DFW_post_system_work(tdbb, dfw_update_format, &desc, 0);
|
2001-05-23 15:26:42 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
return aggregate_public;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2005-05-12 20:28:04 +02:00
|
|
|
static void save_security_class(thread_db* tdbb,
|
|
|
|
const Firebird::MetaName& s_class,
|
2008-07-11 15:50:59 +02:00
|
|
|
const Acl& acl)
|
2001-05-23 15:26:42 +02:00
|
|
|
{
|
|
|
|
/**************************************
|
|
|
|
*
|
|
|
|
* s a v e _ s e c u r i t y _ c l a s s
|
|
|
|
*
|
|
|
|
**************************************
|
|
|
|
*
|
|
|
|
* Functional description
|
|
|
|
* Store or update the named security class.
|
|
|
|
*
|
|
|
|
**************************************/
|
|
|
|
SET_TDBB(tdbb);
|
2007-12-03 16:46:39 +01:00
|
|
|
Database* dbb = tdbb->getDatabase();
|
2001-05-23 15:26:42 +02:00
|
|
|
|
2004-01-21 08:18:30 +01:00
|
|
|
bid blob_id;
|
|
|
|
blb* blob = BLB_create(tdbb, dbb->dbb_sys_trans, &blob_id);
|
2008-07-11 15:50:59 +02:00
|
|
|
size_t length = acl.getCount();
|
2008-07-15 08:24:04 +02:00
|
|
|
const UCHAR* buffer = acl.begin();
|
2008-07-11 15:50:59 +02:00
|
|
|
while (length)
|
|
|
|
{
|
2008-07-15 08:24:04 +02:00
|
|
|
const size_t step = length > ACL_BLOB_BUFFER_SIZE ? ACL_BLOB_BUFFER_SIZE : length;
|
2008-07-11 15:50:59 +02:00
|
|
|
BLB_put_segment(tdbb, blob, buffer, static_cast<USHORT>(step));
|
|
|
|
length -= step;
|
|
|
|
buffer += step;
|
|
|
|
}
|
2001-05-23 15:26:42 +02:00
|
|
|
BLB_close(tdbb, blob);
|
|
|
|
|
2004-03-20 15:57:40 +01:00
|
|
|
jrd_req* request = CMP_find_request(tdbb, irq_grant3, IRQ_REQUESTS);
|
2001-05-23 15:26:42 +02:00
|
|
|
|
2003-12-31 06:36:12 +01:00
|
|
|
bool found = false;
|
2001-05-23 15:26:42 +02:00
|
|
|
FOR(REQUEST_HANDLE request)
|
|
|
|
CLS IN RDB$SECURITY_CLASSES
|
2005-05-12 20:28:04 +02:00
|
|
|
WITH CLS.RDB$SECURITY_CLASS EQ s_class.c_str()
|
2001-05-23 15:26:42 +02:00
|
|
|
if (!REQUEST(irq_grant3))
|
|
|
|
REQUEST(irq_grant3) = request;
|
2003-12-31 06:36:12 +01:00
|
|
|
found = true;
|
2001-05-23 15:26:42 +02:00
|
|
|
MODIFY CLS
|
|
|
|
CLS.RDB$ACL = blob_id;
|
|
|
|
END_MODIFY;
|
|
|
|
END_FOR;
|
|
|
|
|
|
|
|
if (!REQUEST(irq_grant3))
|
|
|
|
REQUEST(irq_grant3) = request;
|
|
|
|
|
|
|
|
if (!found) {
|
2004-02-20 07:43:27 +01:00
|
|
|
request = CMP_find_request(tdbb, irq_grant4, IRQ_REQUESTS);
|
2001-05-23 15:26:42 +02:00
|
|
|
|
|
|
|
STORE(REQUEST_HANDLE request)
|
|
|
|
CLS IN RDB$SECURITY_CLASSES
|
2005-05-12 20:28:04 +02:00
|
|
|
jrd_vtof(s_class.c_str(), CLS.RDB$SECURITY_CLASS,
|
2001-05-23 15:26:42 +02:00
|
|
|
sizeof(CLS.RDB$SECURITY_CLASS));
|
|
|
|
CLS.RDB$ACL = blob_id;
|
|
|
|
END_STORE;
|
|
|
|
|
|
|
|
if (!REQUEST(irq_grant4))
|
|
|
|
REQUEST(irq_grant4) = request;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2004-07-06 07:59:40 +02:00
|
|
|
static SecurityClass::flags_t trans_sql_priv(const TEXT* privileges)
|
2001-05-23 15:26:42 +02:00
|
|
|
{
|
|
|
|
/**************************************
|
|
|
|
*
|
|
|
|
* t r a n s _ s q l _ p r i v
|
|
|
|
*
|
|
|
|
**************************************
|
|
|
|
*
|
|
|
|
* Functional description
|
|
|
|
* Map a SQL privilege letter into an internal privilege bit.
|
|
|
|
*
|
|
|
|
**************************************/
|
2004-07-06 07:59:40 +02:00
|
|
|
SecurityClass::flags_t priv = 0;
|
2001-05-23 15:26:42 +02:00
|
|
|
|
|
|
|
switch (UPPER7(privileges[0])) {
|
|
|
|
case 'S':
|
|
|
|
priv |= SCL_read;
|
|
|
|
break;
|
|
|
|
case 'I':
|
|
|
|
priv |= SCL_sql_insert;
|
|
|
|
break;
|
|
|
|
case 'U':
|
|
|
|
priv |= SCL_sql_update;
|
|
|
|
break;
|
|
|
|
case 'D':
|
|
|
|
priv |= SCL_sql_delete;
|
|
|
|
break;
|
|
|
|
case 'R':
|
|
|
|
priv |= SCL_sql_references;
|
|
|
|
break;
|
|
|
|
case 'X':
|
|
|
|
priv |= SCL_execute;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
return priv;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2008-07-11 15:50:59 +02:00
|
|
|
static SecurityClass::flags_t squeeze_acl(Acl& acl,
|
2005-05-12 20:28:04 +02:00
|
|
|
const Firebird::MetaName& user,
|
|
|
|
SSHORT user_type)
|
2001-05-23 15:26:42 +02:00
|
|
|
{
|
|
|
|
/**************************************
|
|
|
|
*
|
|
|
|
* s q u e e z e _ a c l
|
|
|
|
*
|
|
|
|
**************************************
|
|
|
|
*
|
|
|
|
* Functional description
|
|
|
|
* Walk an access control list looking for a hit. If a hit
|
|
|
|
* is found, return privileges and squeeze out that acl-element.
|
|
|
|
* The caller will use the returned privilege to insert a new
|
|
|
|
* privilege for the input user.
|
|
|
|
*
|
|
|
|
**************************************/
|
2004-07-06 07:59:40 +02:00
|
|
|
UCHAR* dup_acl;
|
|
|
|
SecurityClass::flags_t privilege = 0;
|
2004-05-06 10:42:15 +02:00
|
|
|
UCHAR c;
|
2001-05-23 15:26:42 +02:00
|
|
|
|
|
|
|
/* Make sure that this half-finished acl looks good enough to process. */
|
2008-07-11 15:50:59 +02:00
|
|
|
acl.push(0);
|
2001-05-23 15:26:42 +02:00
|
|
|
|
2008-07-11 15:50:59 +02:00
|
|
|
UCHAR* a = acl.begin();
|
|
|
|
|
|
|
|
if (*a++ != ACL_version)
|
2001-05-23 15:26:42 +02:00
|
|
|
BUGCHECK(160); /* msg 160 wrong ACL version */
|
|
|
|
|
2004-02-20 07:43:27 +01:00
|
|
|
bool hit = false;
|
|
|
|
|
2008-07-11 15:50:59 +02:00
|
|
|
while ( (c = *a++) )
|
2001-05-23 15:26:42 +02:00
|
|
|
switch (c) {
|
|
|
|
case ACL_id_list:
|
2008-07-11 15:50:59 +02:00
|
|
|
dup_acl = a - 1;
|
2004-02-20 07:43:27 +01:00
|
|
|
hit = true;
|
2008-07-11 15:50:59 +02:00
|
|
|
while ( (c = *a++) ) {
|
2001-05-23 15:26:42 +02:00
|
|
|
switch (c) {
|
|
|
|
case id_person:
|
|
|
|
if (user_type != obj_user)
|
2004-02-20 07:43:27 +01:00
|
|
|
hit = false;
|
2008-07-11 15:50:59 +02:00
|
|
|
if (check_string(a, user))
|
2004-02-20 07:43:27 +01:00
|
|
|
hit = false;
|
2001-05-23 15:26:42 +02:00
|
|
|
break;
|
|
|
|
|
|
|
|
case id_sql_role:
|
|
|
|
if (user_type != obj_sql_role)
|
2004-02-20 07:43:27 +01:00
|
|
|
hit = false;
|
2008-07-11 15:50:59 +02:00
|
|
|
if (check_string(a, user))
|
2004-02-20 07:43:27 +01:00
|
|
|
hit = false;
|
2001-05-23 15:26:42 +02:00
|
|
|
break;
|
|
|
|
|
|
|
|
case id_view:
|
|
|
|
if (user_type != obj_view)
|
2004-02-20 07:43:27 +01:00
|
|
|
hit = false;
|
2008-07-11 15:50:59 +02:00
|
|
|
if (check_string(a, user))
|
2004-02-20 07:43:27 +01:00
|
|
|
hit = false;
|
2001-05-23 15:26:42 +02:00
|
|
|
break;
|
|
|
|
|
|
|
|
case id_procedure:
|
|
|
|
if (user_type != obj_procedure)
|
2004-02-20 07:43:27 +01:00
|
|
|
hit = false;
|
2008-07-11 15:50:59 +02:00
|
|
|
if (check_string(a, user))
|
2004-02-20 07:43:27 +01:00
|
|
|
hit = false;
|
2001-05-23 15:26:42 +02:00
|
|
|
break;
|
|
|
|
|
|
|
|
case id_trigger:
|
|
|
|
if (user_type != obj_trigger)
|
2004-02-20 07:43:27 +01:00
|
|
|
hit = false;
|
2008-07-11 15:50:59 +02:00
|
|
|
if (check_string(a, user))
|
2004-02-20 07:43:27 +01:00
|
|
|
hit = false;
|
2001-05-23 15:26:42 +02:00
|
|
|
break;
|
|
|
|
|
|
|
|
case id_project:
|
|
|
|
case id_organization:
|
2004-02-20 07:43:27 +01:00
|
|
|
hit = false;
|
2003-10-29 11:53:47 +01:00
|
|
|
// CVC: What's the idea of calling a function whose only
|
|
|
|
// result is boolean without checking it?
|
2008-07-11 15:50:59 +02:00
|
|
|
check_string(a, user);
|
2001-05-23 15:26:42 +02:00
|
|
|
break;
|
|
|
|
|
|
|
|
case id_views:
|
2004-02-20 07:43:27 +01:00
|
|
|
hit = false;
|
2001-05-23 15:26:42 +02:00
|
|
|
break;
|
|
|
|
|
|
|
|
case id_node:
|
|
|
|
case id_user:
|
2004-07-06 07:59:40 +02:00
|
|
|
{
|
2008-01-16 10:07:24 +01:00
|
|
|
hit = false;
|
|
|
|
// Seems strange with the same increment just after the switch.
|
2008-07-11 15:50:59 +02:00
|
|
|
a += *a + 1;
|
2004-07-06 07:59:40 +02:00
|
|
|
}
|
2008-01-16 10:07:24 +01:00
|
|
|
break;
|
2001-05-23 15:26:42 +02:00
|
|
|
|
|
|
|
case id_group:
|
|
|
|
if (user_type != obj_user_group)
|
2004-02-20 07:43:27 +01:00
|
|
|
hit = false;
|
2008-07-11 15:50:59 +02:00
|
|
|
if (check_string(a, user))
|
2004-02-20 07:43:27 +01:00
|
|
|
hit = false;
|
2001-05-23 15:26:42 +02:00
|
|
|
break;
|
|
|
|
|
|
|
|
default:
|
|
|
|
BUGCHECK(293); /* bad ACL */
|
|
|
|
}
|
2008-07-11 15:50:59 +02:00
|
|
|
a += *a + 1;
|
2001-05-23 15:26:42 +02:00
|
|
|
}
|
|
|
|
break;
|
|
|
|
|
|
|
|
case ACL_priv_list:
|
|
|
|
if (hit) {
|
2008-07-11 15:50:59 +02:00
|
|
|
while ( (c = *a++) )
|
2001-05-23 15:26:42 +02:00
|
|
|
switch (c) {
|
|
|
|
case priv_control:
|
|
|
|
privilege |= SCL_control;
|
|
|
|
break;
|
|
|
|
|
|
|
|
case priv_read:
|
|
|
|
privilege |= SCL_read;
|
|
|
|
break;
|
|
|
|
|
|
|
|
case priv_write:
|
|
|
|
privilege |= SCL_write;
|
|
|
|
break;
|
|
|
|
|
|
|
|
case priv_sql_insert:
|
|
|
|
privilege |= SCL_sql_insert;
|
|
|
|
break;
|
|
|
|
|
|
|
|
case priv_sql_delete:
|
|
|
|
privilege |= SCL_sql_delete;
|
|
|
|
break;
|
|
|
|
|
|
|
|
case priv_sql_references:
|
|
|
|
privilege |= SCL_sql_references;
|
|
|
|
break;
|
|
|
|
|
|
|
|
case priv_sql_update:
|
|
|
|
privilege |= SCL_sql_update;
|
|
|
|
break;
|
|
|
|
|
|
|
|
case priv_delete:
|
|
|
|
privilege |= SCL_delete;
|
|
|
|
break;
|
|
|
|
|
|
|
|
case priv_grant:
|
|
|
|
privilege |= SCL_grant;
|
|
|
|
break;
|
|
|
|
|
|
|
|
case priv_protect:
|
|
|
|
privilege |= SCL_protect;
|
|
|
|
break;
|
|
|
|
|
|
|
|
case priv_execute:
|
|
|
|
privilege |= SCL_execute;
|
|
|
|
break;
|
|
|
|
|
|
|
|
default:
|
|
|
|
BUGCHECK(293); /* bad ACL */
|
|
|
|
}
|
|
|
|
/* Squeeze out duplicate acl element. */
|
2008-07-11 15:50:59 +02:00
|
|
|
acl.remove(dup_acl, a);
|
|
|
|
a = dup_acl;
|
2001-05-23 15:26:42 +02:00
|
|
|
}
|
|
|
|
else
|
2008-07-11 15:50:59 +02:00
|
|
|
while (*a++);
|
2001-05-23 15:26:42 +02:00
|
|
|
break;
|
|
|
|
|
|
|
|
default:
|
|
|
|
BUGCHECK(293); /* bad ACL */
|
|
|
|
}
|
|
|
|
|
2008-07-11 15:50:59 +02:00
|
|
|
// remove added extra '\0' byte
|
|
|
|
acl.pop();
|
|
|
|
|
2001-05-23 15:26:42 +02:00
|
|
|
return privilege;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2005-05-12 20:28:04 +02:00
|
|
|
static bool check_string(const UCHAR* acl, const Firebird::MetaName& name)
|
2001-05-23 15:26:42 +02:00
|
|
|
{
|
|
|
|
/**************************************
|
|
|
|
*
|
|
|
|
* c h e c k _ s t r i n g
|
|
|
|
*
|
|
|
|
**************************************
|
|
|
|
*
|
|
|
|
* Functional description
|
|
|
|
* Check a string against an acl string. If they don't match,
|
2003-10-29 11:53:47 +01:00
|
|
|
* return true.
|
2001-05-23 15:26:42 +02:00
|
|
|
*
|
|
|
|
**************************************/
|
|
|
|
/* JPN: Since Kanji User names are not allowed, No need to fix this UPPER loop. */
|
|
|
|
|
2004-02-20 07:43:27 +01:00
|
|
|
USHORT l = *acl++;
|
2005-05-12 20:28:04 +02:00
|
|
|
const TEXT* string = name.c_str();
|
2004-02-20 07:43:27 +01:00
|
|
|
if (l)
|
2005-05-12 20:28:04 +02:00
|
|
|
{
|
|
|
|
do
|
|
|
|
{
|
2004-05-06 10:42:15 +02:00
|
|
|
const UCHAR c1 = *acl++;
|
2003-10-29 11:53:47 +01:00
|
|
|
const TEXT c2 = *string++;
|
2001-05-23 15:26:42 +02:00
|
|
|
if (UPPER7(c1) != UPPER7(c2))
|
2005-05-12 20:28:04 +02:00
|
|
|
{
|
2003-10-29 11:53:47 +01:00
|
|
|
return true;
|
2005-05-12 20:28:04 +02:00
|
|
|
}
|
2001-05-23 15:26:42 +02:00
|
|
|
} while (--l);
|
2005-05-12 20:28:04 +02:00
|
|
|
}
|
2001-05-23 15:26:42 +02:00
|
|
|
|
2003-10-29 11:53:47 +01:00
|
|
|
return (*string && *string != ' ') ? true : false;
|
2001-05-23 15:26:42 +02:00
|
|
|
}
|
2003-10-29 11:53:47 +01:00
|
|
|
|