mirror of
https://github.com/FirebirdSQL/firebird.git
synced 2025-01-24 00:03:03 +01:00
Fixed CORE-1957 & CORE-216: too many grants lose privileges. ACLs cleanup.
This commit is contained in:
parent
6fb4e12bb3
commit
aeba7e6444
@ -212,6 +212,10 @@ public:
|
||||
memmove(data + index, data + index + 1, sizeof(T) * (--count - index));
|
||||
return &data[index];
|
||||
}
|
||||
T* remove(T* itrFrom, T* itrTo)
|
||||
{
|
||||
return removeRange(itrFrom - begin(), itrTo - begin());
|
||||
}
|
||||
void shrink(size_t newCount)
|
||||
{
|
||||
fb_assert(newCount <= count);
|
||||
@ -254,6 +258,12 @@ public:
|
||||
memcpy(data + count, L.data, sizeof(T) * L.count);
|
||||
count += L.count;
|
||||
}
|
||||
void assign(const Array<T, Storage>& L)
|
||||
{
|
||||
ensureCapacity(L.count);
|
||||
memcpy(data, L.data, sizeof(T) * L.count);
|
||||
count = L.count;
|
||||
}
|
||||
// NOTE: getCount method must be signal safe
|
||||
// Used as such in GlobalRWLock::blockingAstHandler
|
||||
size_t getCount() const { return count; }
|
||||
|
@ -64,69 +64,37 @@ const SecurityClass::flags_t VIEW_PRIVS = SCL_read | SCL_write | SCL_delete;
|
||||
const ULONG ACL_BUFFER_SIZE = 4096;
|
||||
static const char* DEFAULT_CLASS = "SQL$DEFAULT";
|
||||
|
||||
#define CHECK_ACL_BOUND(to, start, length_ptr, move_length)\
|
||||
{\
|
||||
if (((start).begin() + *length_ptr) < (to + move_length)) {\
|
||||
GRANT_realloc_acl(start, &to, length_ptr);\
|
||||
}\
|
||||
}
|
||||
#define CHECK_AND_MOVE(to, from, start, length_ptr) {CHECK_ACL_BOUND (to, start, length_ptr, 1); *(to)++ = from;}
|
||||
#define CHECK_MOVE_INCR(to, from, start, length_ptr) {CHECK_ACL_BOUND (to, start, length_ptr, 1); *(to)++ = (from)++;}
|
||||
inline void CHECK_AND_MOVE(Acl& to, UCHAR from)
|
||||
{
|
||||
to.add(from);
|
||||
}
|
||||
|
||||
DATABASE DB = STATIC "yachts.lnk";
|
||||
|
||||
static void define_default_class(thread_db*, const TEXT*, Firebird::MetaName&, const UCHAR*, USHORT);
|
||||
static void define_default_class(thread_db*, const TEXT*, Firebird::MetaName&, const Acl&);
|
||||
#ifdef NOT_USED_OR_REPLACED
|
||||
static void delete_security_class(thread_db*, const TEXT*);
|
||||
#endif
|
||||
static void finish_security_class(UCHAR**, SecurityClass::flags_t, Firebird::UCharBuffer&, ULONG*);
|
||||
static void finish_security_class(Acl&, SecurityClass::flags_t);
|
||||
static void get_object_info(thread_db*, const TEXT*, SSHORT,
|
||||
Firebird::MetaName&, Firebird::MetaName&, Firebird::MetaName&, bool&);
|
||||
static SecurityClass::flags_t get_public_privs(thread_db*, const TEXT*, SSHORT);
|
||||
static void get_user_privs(thread_db*, UCHAR**, const TEXT*, SSHORT, const Firebird::MetaName&,
|
||||
SecurityClass::flags_t, Firebird::UCharBuffer&, ULONG*);
|
||||
static void grant_user(UCHAR**, const Firebird::MetaName&, SSHORT, SecurityClass::flags_t,
|
||||
Firebird::UCharBuffer&, ULONG*);
|
||||
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);
|
||||
#ifdef NOT_USED_OR_REPLACED
|
||||
static void grant_views(TEXT**, SecurityClass::flags_t, Firebird::UCharBuffer&, ULONG*);
|
||||
static void grant_views(TEXT**, SecurityClass::flags_t);
|
||||
static void purge_default_class(TEXT*, SSHORT);
|
||||
#endif
|
||||
static SecurityClass::flags_t save_field_privileges(thread_db*, Firebird::UCharBuffer&, UCHAR**,
|
||||
static SecurityClass::flags_t save_field_privileges(thread_db*, Acl&,
|
||||
const TEXT*, const Firebird::MetaName&,
|
||||
SecurityClass::flags_t, ULONG*);
|
||||
static void save_security_class(thread_db*, const Firebird::MetaName&, const UCHAR*, USHORT);
|
||||
SecurityClass::flags_t);
|
||||
static void save_security_class(thread_db*, const Firebird::MetaName&, const Acl&);
|
||||
static SecurityClass::flags_t trans_sql_priv(const TEXT*);
|
||||
static SecurityClass::flags_t squeeze_acl(UCHAR*, UCHAR**, const Firebird::MetaName&, SSHORT);
|
||||
static SecurityClass::flags_t squeeze_acl(Acl&, const Firebird::MetaName&, SSHORT);
|
||||
static bool check_string(const UCHAR*, const Firebird::MetaName&);
|
||||
|
||||
|
||||
void GRANT_realloc_acl(Firebird::UCharBuffer& start_ptr,
|
||||
UCHAR** write_ptr,
|
||||
ULONG* buffer_length)
|
||||
{
|
||||
/**************************************
|
||||
*
|
||||
* G R A N T _ r e a l l o c _ a c l
|
||||
*
|
||||
**************************************
|
||||
*
|
||||
* Functional description
|
||||
* The ACl list is greater than the current length, Increase it by
|
||||
* MAX_AXL_SIZE. Do a ERR_punt in case of no memory!
|
||||
*
|
||||
**************************************/
|
||||
|
||||
const ULONG old_offset = *write_ptr - start_ptr.begin();
|
||||
const ULONG realloc_length = *buffer_length + ACL_BUFFER_SIZE;
|
||||
|
||||
// realloc the new length, ERR_punt incase of no memory
|
||||
// the write_ptr is set back to the same offset in the new buffer
|
||||
*write_ptr = start_ptr.getBuffer(realloc_length) + old_offset;
|
||||
|
||||
*buffer_length = realloc_length;
|
||||
}
|
||||
|
||||
|
||||
bool GRANT_privileges( thread_db* tdbb, SSHORT phase, DeferredWork* work,
|
||||
jrd_tra*) // unused param, makes dfw.epp happy
|
||||
{
|
||||
@ -150,7 +118,8 @@ bool GRANT_privileges( thread_db* tdbb, SSHORT phase, DeferredWork* work,
|
||||
|
||||
case 3:
|
||||
{
|
||||
ULONG length = ACL_BUFFER_SIZE, *length_ptr = &length;
|
||||
ULONG length = ACL_BUFFER_SIZE;
|
||||
ULONG* length_ptr = &length;
|
||||
ULONG default_length = ACL_BUFFER_SIZE;
|
||||
ULONG* default_length_ptr = &default_length;
|
||||
|
||||
@ -169,52 +138,29 @@ bool GRANT_privileges( thread_db* tdbb, SSHORT phase, DeferredWork* work,
|
||||
}
|
||||
|
||||
/* start the acl off by giving the owner all privileges */
|
||||
Firebird::UCharBuffer str_buffer;
|
||||
Firebird::UCharBuffer str_default_buffer;
|
||||
Acl acl, default_acl;
|
||||
|
||||
UCHAR* acl = str_buffer.getBuffer(ACL_BUFFER_SIZE);
|
||||
str_default_buffer.getBuffer(ACL_BUFFER_SIZE);
|
||||
|
||||
CHECK_AND_MOVE(acl, ACL_version, str_buffer, length_ptr);
|
||||
grant_user(&acl,
|
||||
owner,
|
||||
obj_user,
|
||||
((work->dfw_id == obj_procedure) ?
|
||||
(SCL_execute | OWNER_PRIVS) : OWNER_PRIVS),
|
||||
str_buffer,
|
||||
length_ptr);
|
||||
CHECK_AND_MOVE(acl, ACL_version);
|
||||
grant_user(acl, owner, obj_user,
|
||||
((work->dfw_id == obj_procedure) ? (SCL_execute | OWNER_PRIVS) : OWNER_PRIVS));
|
||||
|
||||
/* Pick up any relation-level privileges */
|
||||
|
||||
const SecurityClass::flags_t public_priv =
|
||||
get_public_privs(tdbb, work->dfw_name.c_str(), work->dfw_id);
|
||||
get_user_privs(tdbb, &acl, work->dfw_name.c_str(), work->dfw_id,
|
||||
owner, public_priv, str_buffer, length_ptr);
|
||||
get_user_privs(tdbb, acl, work->dfw_name.c_str(), work->dfw_id, owner, public_priv);
|
||||
|
||||
if (work->dfw_id == obj_relation)
|
||||
{
|
||||
/* If we have the space to copy the acl list
|
||||
no need to realloc */
|
||||
if (length > default_length) {
|
||||
str_default_buffer.getBuffer(length);
|
||||
default_length = length;
|
||||
}
|
||||
/* 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. */
|
||||
|
||||
memcpy(str_default_buffer.begin(), str_buffer.begin(),
|
||||
(int) (acl - str_buffer.begin()));
|
||||
UCHAR* default_acl =
|
||||
str_default_buffer.begin() + (acl - str_buffer.begin());
|
||||
const UCHAR* const temp_acl = acl;
|
||||
default_acl.assign(acl);
|
||||
|
||||
const SecurityClass::flags_t aggregate_public =
|
||||
save_field_privileges(tdbb, str_buffer,
|
||||
&acl, work->dfw_name.c_str(),
|
||||
owner, public_priv,
|
||||
length_ptr);
|
||||
save_field_privileges(tdbb, acl, work->dfw_name.c_str(), owner, public_priv);
|
||||
|
||||
/* SQL tables don't need the 'all priviliges to all views' acl anymore.
|
||||
This special acl was only generated for SQL. */
|
||||
@ -224,15 +170,11 @@ bool GRANT_privileges( thread_db* tdbb, SSHORT phase, DeferredWork* work,
|
||||
|
||||
/* finish off and store the security class for the relation */
|
||||
|
||||
finish_security_class(&acl, aggregate_public, str_buffer,
|
||||
length_ptr);
|
||||
finish_security_class(acl, aggregate_public);
|
||||
|
||||
save_security_class(tdbb,
|
||||
s_class,
|
||||
str_buffer.begin(),
|
||||
(USHORT)(acl - str_buffer.begin()));
|
||||
save_security_class(tdbb, s_class, acl);
|
||||
|
||||
if (temp_acl != acl) /* relation privs were added? */
|
||||
if (acl.getCount() != default_acl.getCount()) /* relation privs were added? */
|
||||
restrct = true;
|
||||
|
||||
/* if there have been privileges added at the relation level which
|
||||
@ -241,21 +183,13 @@ bool GRANT_privileges( thread_db* tdbb, SSHORT phase, DeferredWork* work,
|
||||
|
||||
if (restrct)
|
||||
{
|
||||
finish_security_class(&default_acl, public_priv,
|
||||
str_default_buffer,
|
||||
default_length_ptr);
|
||||
define_default_class(
|
||||
tdbb,
|
||||
work->dfw_name.c_str(),
|
||||
default_class,
|
||||
str_default_buffer.begin(),
|
||||
(USHORT)(default_acl - str_default_buffer.begin()));
|
||||
finish_security_class(default_acl, public_priv);
|
||||
define_default_class(tdbb, work->dfw_name.c_str(), default_class, default_acl);
|
||||
}
|
||||
}
|
||||
else {
|
||||
finish_security_class(&acl, public_priv, str_buffer, length_ptr);
|
||||
save_security_class(tdbb, s_class, str_buffer.begin(),
|
||||
(USHORT)(acl - str_buffer.begin()));
|
||||
finish_security_class(acl, public_priv);
|
||||
save_security_class(tdbb, s_class, acl);
|
||||
}
|
||||
|
||||
break;
|
||||
@ -276,7 +210,7 @@ static void define_default_class(
|
||||
thread_db* tdbb,
|
||||
const TEXT* relation_name,
|
||||
Firebird::MetaName& default_class,
|
||||
const UCHAR* buffer, USHORT length)
|
||||
const Acl& acl)
|
||||
{
|
||||
/**************************************
|
||||
*
|
||||
@ -323,7 +257,7 @@ static void define_default_class(
|
||||
REQUEST(irq_grant7) = request;
|
||||
}
|
||||
|
||||
save_security_class(tdbb, default_class, buffer, length);
|
||||
save_security_class(tdbb, default_class, acl);
|
||||
|
||||
dsc desc;
|
||||
desc.dsc_dtype = dtype_text;
|
||||
@ -365,10 +299,7 @@ static void delete_security_class( thread_db* tdbb, const TEXT* s_class)
|
||||
#endif // NOT_USED_OR_REPLACED
|
||||
|
||||
|
||||
static void finish_security_class(UCHAR** acl_ptr,
|
||||
SecurityClass::flags_t public_priv,
|
||||
Firebird::UCharBuffer& start_ptr,
|
||||
ULONG* length_ptr)
|
||||
static void finish_security_class(Acl& acl, SecurityClass::flags_t public_priv)
|
||||
{
|
||||
/**************************************
|
||||
*
|
||||
@ -381,16 +312,12 @@ static void finish_security_class(UCHAR** acl_ptr,
|
||||
* in a wildcard for any public privileges.
|
||||
*
|
||||
**************************************/
|
||||
UCHAR* acl = *acl_ptr;
|
||||
|
||||
if (public_priv) {
|
||||
CHECK_AND_MOVE(acl, ACL_id_list, start_ptr, length_ptr);
|
||||
SCL_move_priv(&acl, public_priv, start_ptr, length_ptr);
|
||||
CHECK_AND_MOVE(acl, ACL_id_list);
|
||||
SCL_move_priv(public_priv, acl);
|
||||
}
|
||||
|
||||
CHECK_AND_MOVE(acl, ACL_end, start_ptr, length_ptr);
|
||||
|
||||
*acl_ptr = acl;
|
||||
CHECK_AND_MOVE(acl, ACL_end);
|
||||
}
|
||||
|
||||
|
||||
@ -503,13 +430,11 @@ static void get_object_info(thread_db* tdbb,
|
||||
|
||||
|
||||
static void get_user_privs(thread_db* tdbb,
|
||||
UCHAR** acl_ptr,
|
||||
Acl& acl,
|
||||
const TEXT* object_name,
|
||||
SSHORT obj_type,
|
||||
const Firebird::MetaName& owner,
|
||||
SecurityClass::flags_t public_priv,
|
||||
Firebird::UCharBuffer& start_ptr,
|
||||
ULONG* length_ptr)
|
||||
SecurityClass::flags_t public_priv)
|
||||
{
|
||||
/**************************************
|
||||
*
|
||||
@ -524,7 +449,6 @@ static void get_user_privs(thread_db* tdbb,
|
||||
SET_TDBB(tdbb);
|
||||
Database* dbb = tdbb->getDatabase();
|
||||
|
||||
UCHAR* acl = *acl_ptr;
|
||||
Firebird::MetaName user;
|
||||
SSHORT user_type = -2;
|
||||
SecurityClass::flags_t priv = 0;
|
||||
@ -548,7 +472,7 @@ static void get_user_privs(thread_db* tdbb,
|
||||
{
|
||||
if (user.length())
|
||||
{
|
||||
grant_user(&acl, user, user_type, priv, start_ptr, length_ptr);
|
||||
grant_user(acl, user, user_type, priv);
|
||||
}
|
||||
user_type = PRV.RDB$USER_TYPE;
|
||||
if (user_type == obj_user)
|
||||
@ -568,18 +492,14 @@ static void get_user_privs(thread_db* tdbb,
|
||||
REQUEST(irq_grant2) = request;
|
||||
|
||||
if (user.length())
|
||||
grant_user(&acl, user, user_type, priv, start_ptr, length_ptr);
|
||||
|
||||
*acl_ptr = acl;
|
||||
grant_user(acl, user, user_type, priv);
|
||||
}
|
||||
|
||||
|
||||
static void grant_user(UCHAR** acl_ptr,
|
||||
static void grant_user(Acl& acl,
|
||||
const Firebird::MetaName& user,
|
||||
SSHORT user_type,
|
||||
SecurityClass::flags_t privs,
|
||||
Firebird::UCharBuffer& start_ptr,
|
||||
ULONG* length_ptr)
|
||||
SecurityClass::flags_t privs)
|
||||
{
|
||||
/**************************************
|
||||
*
|
||||
@ -591,32 +511,30 @@ static void grant_user(UCHAR** acl_ptr,
|
||||
* Grant privileges to a particular user.
|
||||
*
|
||||
**************************************/
|
||||
UCHAR* acl = *acl_ptr;
|
||||
|
||||
CHECK_AND_MOVE(acl, ACL_id_list, start_ptr, length_ptr);
|
||||
CHECK_AND_MOVE(acl, ACL_id_list);
|
||||
switch (user_type) {
|
||||
case obj_user_group:
|
||||
CHECK_AND_MOVE(acl, id_group, start_ptr, length_ptr);
|
||||
CHECK_AND_MOVE(acl, id_group);
|
||||
break;
|
||||
|
||||
case obj_sql_role:
|
||||
CHECK_AND_MOVE(acl, id_sql_role, start_ptr, length_ptr);
|
||||
CHECK_AND_MOVE(acl, id_sql_role);
|
||||
break;
|
||||
|
||||
case obj_user:
|
||||
CHECK_AND_MOVE(acl, id_person, start_ptr, length_ptr);
|
||||
CHECK_AND_MOVE(acl, id_person);
|
||||
break;
|
||||
|
||||
case obj_procedure:
|
||||
CHECK_AND_MOVE(acl, id_procedure, start_ptr, length_ptr);
|
||||
CHECK_AND_MOVE(acl, id_procedure);
|
||||
break;
|
||||
|
||||
case obj_trigger:
|
||||
CHECK_AND_MOVE(acl, id_trigger, start_ptr, length_ptr);
|
||||
CHECK_AND_MOVE(acl, id_trigger);
|
||||
break;
|
||||
|
||||
case obj_view:
|
||||
CHECK_AND_MOVE(acl, id_view, start_ptr, length_ptr);
|
||||
CHECK_AND_MOVE(acl, id_view);
|
||||
break;
|
||||
|
||||
default:
|
||||
@ -625,23 +543,18 @@ static void grant_user(UCHAR** acl_ptr,
|
||||
}
|
||||
|
||||
const UCHAR length = user.length();
|
||||
CHECK_AND_MOVE(acl, length, start_ptr, length_ptr);
|
||||
CHECK_AND_MOVE(acl, length);
|
||||
if (length) {
|
||||
CHECK_ACL_BOUND(acl, start_ptr, length_ptr, length);
|
||||
memcpy(acl, user.c_str(), length);
|
||||
acl += length;
|
||||
acl.add(reinterpret_cast<const UCHAR*>(user.c_str()), length);
|
||||
}
|
||||
|
||||
SCL_move_priv(&acl, privs, start_ptr, length_ptr);
|
||||
|
||||
*acl_ptr = acl;
|
||||
SCL_move_priv(privs, acl);
|
||||
}
|
||||
|
||||
#ifdef NOT_USED_OR_REPLACED
|
||||
static void grant_views(
|
||||
UCHAR** acl_ptr,
|
||||
SecurityClass::flags_t privs, Firebird::UCharBuffer& start_ptr,
|
||||
ULONG* length_ptr)
|
||||
Acl& acl,
|
||||
SecurityClass::flags_t privs)
|
||||
{
|
||||
/**************************************
|
||||
*
|
||||
@ -653,14 +566,10 @@ static void grant_views(
|
||||
* Grant privileges to all views.
|
||||
*
|
||||
**************************************/
|
||||
UCHAR* acl = *acl_ptr;
|
||||
|
||||
CHECK_AND_MOVE(acl, ACL_id_list, start_ptr, length_ptr);
|
||||
CHECK_AND_MOVE(acl, id_views, start_ptr, length_ptr);
|
||||
CHECK_AND_MOVE(acl, 0, start_ptr, length_ptr);
|
||||
SCL_move_priv(&acl, privs, start_ptr, length_ptr);
|
||||
|
||||
*acl_ptr = acl;
|
||||
CHECK_AND_MOVE(acl, ACL_id_list);
|
||||
CHECK_AND_MOVE(acl, id_views);
|
||||
CHECK_AND_MOVE(acl, 0);
|
||||
SCL_move_priv(privs, acl);
|
||||
}
|
||||
|
||||
|
||||
@ -715,12 +624,10 @@ static void purge_default_class( TEXT* object_name, SSHORT obj_type)
|
||||
|
||||
|
||||
static SecurityClass::flags_t save_field_privileges(thread_db* tdbb,
|
||||
Firebird::UCharBuffer& str_relation_buffer,
|
||||
UCHAR** acl_ptr,
|
||||
Acl& relation_acl,
|
||||
const TEXT* relation_name,
|
||||
const Firebird::MetaName& owner,
|
||||
SecurityClass::flags_t public_priv,
|
||||
ULONG* length_ptr)
|
||||
SecurityClass::flags_t public_priv)
|
||||
{
|
||||
/**************************************
|
||||
*
|
||||
@ -735,30 +642,13 @@ static SecurityClass::flags_t save_field_privileges(thread_db* tdbb,
|
||||
* security class to be effective.
|
||||
*
|
||||
**************************************/
|
||||
Firebird::UCharBuffer str_field_buffer;
|
||||
Firebird::UCharBuffer str_field_buffer_start;
|
||||
Acl field_acl, acl_start;
|
||||
|
||||
SET_TDBB(tdbb);
|
||||
Database* dbb = tdbb->getDatabase();
|
||||
|
||||
// initialize the field-level acl buffer to include all relation-level privs
|
||||
str_field_buffer_start.getBuffer(*length_ptr - 1);
|
||||
str_field_buffer.getBuffer(*length_ptr - 1);
|
||||
|
||||
ULONG field_length, start_length;
|
||||
field_length = start_length = *length_ptr;
|
||||
ULONG* field_length_ptr = &field_length;
|
||||
|
||||
memcpy(str_field_buffer.begin(), str_relation_buffer.begin(),
|
||||
(int) (*acl_ptr - str_relation_buffer.begin()));
|
||||
const int field_buffer_start_index = (int) (*acl_ptr - str_relation_buffer.begin());
|
||||
UCHAR* field_acl = str_field_buffer.begin() + field_buffer_start_index;
|
||||
UCHAR* relation_acl = str_relation_buffer.begin() + field_buffer_start_index;
|
||||
|
||||
int i;
|
||||
/* remember this starting point for subsequent fields. */
|
||||
for (i = 0; field_buffer_start_index > i;
|
||||
i++, str_field_buffer_start[i] = str_field_buffer[i]);
|
||||
field_acl.assign(relation_acl);
|
||||
acl_start.assign(field_acl);
|
||||
|
||||
Firebird::MetaName field_name, user, s_class;
|
||||
SecurityClass::flags_t aggregate_public = public_priv;
|
||||
@ -796,31 +686,11 @@ static SecurityClass::flags_t save_field_privileges(thread_db* tdbb,
|
||||
if (user != "PUBLIC")
|
||||
{
|
||||
const SecurityClass::flags_t field_priv =
|
||||
public_priv |
|
||||
priv |
|
||||
squeeze_acl(str_field_buffer.begin(),
|
||||
&field_acl,
|
||||
user,
|
||||
user_type);
|
||||
grant_user(&field_acl,
|
||||
user,
|
||||
user_type,
|
||||
field_priv,
|
||||
str_field_buffer,
|
||||
field_length_ptr);
|
||||
public_priv | priv | squeeze_acl(field_acl, user, user_type);
|
||||
grant_user(field_acl, user, user_type, field_priv);
|
||||
const SecurityClass::flags_t relation_priv =
|
||||
public_priv |
|
||||
priv |
|
||||
squeeze_acl(str_relation_buffer.begin(),
|
||||
&relation_acl,
|
||||
user,
|
||||
user_type);
|
||||
grant_user(&relation_acl,
|
||||
user,
|
||||
user_type,
|
||||
relation_priv,
|
||||
str_relation_buffer,
|
||||
length_ptr);
|
||||
public_priv | priv | squeeze_acl(relation_acl, user, user_type);
|
||||
grant_user(relation_acl, user, user_type, relation_priv);
|
||||
}
|
||||
else
|
||||
{
|
||||
@ -844,15 +714,8 @@ static SecurityClass::flags_t save_field_privileges(thread_db* tdbb,
|
||||
|
||||
if (field_name.length()) {
|
||||
aggregate_public |= field_public;
|
||||
finish_security_class(&field_acl,
|
||||
(field_public | public_priv),
|
||||
str_field_buffer,
|
||||
field_length_ptr);
|
||||
save_security_class(
|
||||
tdbb,
|
||||
s_class,
|
||||
str_field_buffer.begin(),
|
||||
(USHORT)(field_acl - str_field_buffer.begin()));
|
||||
finish_security_class(field_acl, (field_public | public_priv));
|
||||
save_security_class(tdbb, s_class, field_acl);
|
||||
}
|
||||
|
||||
/* initialize for new field */
|
||||
@ -891,15 +754,7 @@ static SecurityClass::flags_t save_field_privileges(thread_db* tdbb,
|
||||
field_public = 0;
|
||||
|
||||
/* restart a security class at the end of the relation-level privs */
|
||||
|
||||
i = 0;
|
||||
while (field_buffer_start_index > i)
|
||||
{
|
||||
++i;
|
||||
str_field_buffer[i] = str_field_buffer_start[i];
|
||||
}
|
||||
|
||||
field_acl = str_field_buffer.begin() + field_buffer_start_index;
|
||||
field_acl.assign(acl_start);
|
||||
}
|
||||
|
||||
priv |= trans_sql_priv(PRV.RDB$PRIVILEGE);
|
||||
@ -921,31 +776,11 @@ static SecurityClass::flags_t save_field_privileges(thread_db* tdbb,
|
||||
if (user != "PUBLIC")
|
||||
{
|
||||
const SecurityClass::flags_t field_priv =
|
||||
public_priv |
|
||||
priv |
|
||||
squeeze_acl(str_field_buffer.begin(),
|
||||
&field_acl,
|
||||
user,
|
||||
user_type);
|
||||
grant_user(&field_acl,
|
||||
user,
|
||||
user_type,
|
||||
field_priv,
|
||||
str_field_buffer,
|
||||
field_length_ptr);
|
||||
public_priv | priv | squeeze_acl(field_acl, user, user_type);
|
||||
grant_user(field_acl, user, user_type, field_priv);
|
||||
const SecurityClass::flags_t relation_priv =
|
||||
public_priv |
|
||||
priv |
|
||||
squeeze_acl(str_relation_buffer.begin(),
|
||||
&relation_acl,
|
||||
user,
|
||||
user_type);
|
||||
grant_user(&relation_acl,
|
||||
user,
|
||||
user_type,
|
||||
relation_priv,
|
||||
str_relation_buffer,
|
||||
length_ptr);
|
||||
public_priv | priv | squeeze_acl(relation_acl, user, user_type);
|
||||
grant_user(relation_acl, user, user_type, relation_priv);
|
||||
}
|
||||
else
|
||||
{
|
||||
@ -958,14 +793,8 @@ static SecurityClass::flags_t save_field_privileges(thread_db* tdbb,
|
||||
if (field_name.length())
|
||||
{
|
||||
aggregate_public |= field_public;
|
||||
finish_security_class(&field_acl,
|
||||
(field_public | public_priv),
|
||||
str_field_buffer,
|
||||
field_length_ptr);
|
||||
save_security_class(tdbb,
|
||||
s_class,
|
||||
str_field_buffer.begin(),
|
||||
(USHORT)(field_acl - str_field_buffer.begin()));
|
||||
finish_security_class(field_acl, (field_public | public_priv));
|
||||
save_security_class(tdbb, s_class, field_acl);
|
||||
|
||||
dsc desc;
|
||||
desc.dsc_dtype = dtype_text;
|
||||
@ -977,16 +806,13 @@ static SecurityClass::flags_t save_field_privileges(thread_db* tdbb,
|
||||
DFW_post_system_work(tdbb, dfw_update_format, &desc, 0);
|
||||
}
|
||||
|
||||
*acl_ptr = relation_acl;
|
||||
|
||||
return aggregate_public;
|
||||
}
|
||||
|
||||
|
||||
static void save_security_class(thread_db* tdbb,
|
||||
const Firebird::MetaName& s_class,
|
||||
const UCHAR* buffer,
|
||||
USHORT length)
|
||||
const Acl& acl)
|
||||
{
|
||||
/**************************************
|
||||
*
|
||||
@ -1003,7 +829,15 @@ static void save_security_class(thread_db* tdbb,
|
||||
|
||||
bid blob_id;
|
||||
blb* blob = BLB_create(tdbb, dbb->dbb_sys_trans, &blob_id);
|
||||
BLB_put_segment(tdbb, blob, buffer, length);
|
||||
size_t length = acl.getCount();
|
||||
const UCHAR *buffer = acl.begin();
|
||||
while (length)
|
||||
{
|
||||
size_t step = length > ACL_BLOB_BUFFER_SIZE ? ACL_BLOB_BUFFER_SIZE : length;
|
||||
BLB_put_segment(tdbb, blob, buffer, static_cast<USHORT>(step));
|
||||
length -= step;
|
||||
buffer += step;
|
||||
}
|
||||
BLB_close(tdbb, blob);
|
||||
|
||||
jrd_req* request = CMP_find_request(tdbb, irq_grant3, IRQ_REQUESTS);
|
||||
@ -1078,8 +912,7 @@ static SecurityClass::flags_t trans_sql_priv(const TEXT* privileges)
|
||||
}
|
||||
|
||||
|
||||
static SecurityClass::flags_t squeeze_acl(UCHAR* acl_base,
|
||||
UCHAR** acl_ptr,
|
||||
static SecurityClass::flags_t squeeze_acl(Acl& acl,
|
||||
const Firebird::MetaName& user,
|
||||
SSHORT user_type)
|
||||
{
|
||||
@ -1101,53 +934,54 @@ static SecurityClass::flags_t squeeze_acl(UCHAR* acl_base,
|
||||
UCHAR c;
|
||||
|
||||
/* Make sure that this half-finished acl looks good enough to process. */
|
||||
**acl_ptr = 0;
|
||||
UCHAR* acl = acl_base;
|
||||
acl.push(0);
|
||||
|
||||
if (*acl++ != ACL_version)
|
||||
UCHAR* a = acl.begin();
|
||||
|
||||
if (*a++ != ACL_version)
|
||||
BUGCHECK(160); /* msg 160 wrong ACL version */
|
||||
|
||||
bool hit = false;
|
||||
|
||||
while ( (c = *acl++) )
|
||||
while ( (c = *a++) )
|
||||
switch (c) {
|
||||
case ACL_id_list:
|
||||
dup_acl = acl - 1;
|
||||
dup_acl = a - 1;
|
||||
hit = true;
|
||||
while ( (c = *acl++) ) {
|
||||
while ( (c = *a++) ) {
|
||||
switch (c) {
|
||||
case id_person:
|
||||
if (user_type != obj_user)
|
||||
hit = false;
|
||||
if (check_string(acl, user))
|
||||
if (check_string(a, user))
|
||||
hit = false;
|
||||
break;
|
||||
|
||||
case id_sql_role:
|
||||
if (user_type != obj_sql_role)
|
||||
hit = false;
|
||||
if (check_string(acl, user))
|
||||
if (check_string(a, user))
|
||||
hit = false;
|
||||
break;
|
||||
|
||||
case id_view:
|
||||
if (user_type != obj_view)
|
||||
hit = false;
|
||||
if (check_string(acl, user))
|
||||
if (check_string(a, user))
|
||||
hit = false;
|
||||
break;
|
||||
|
||||
case id_procedure:
|
||||
if (user_type != obj_procedure)
|
||||
hit = false;
|
||||
if (check_string(acl, user))
|
||||
if (check_string(a, user))
|
||||
hit = false;
|
||||
break;
|
||||
|
||||
case id_trigger:
|
||||
if (user_type != obj_trigger)
|
||||
hit = false;
|
||||
if (check_string(acl, user))
|
||||
if (check_string(a, user))
|
||||
hit = false;
|
||||
break;
|
||||
|
||||
@ -1156,7 +990,7 @@ static SecurityClass::flags_t squeeze_acl(UCHAR* acl_base,
|
||||
hit = false;
|
||||
// CVC: What's the idea of calling a function whose only
|
||||
// result is boolean without checking it?
|
||||
check_string(acl, user);
|
||||
check_string(a, user);
|
||||
break;
|
||||
|
||||
case id_views:
|
||||
@ -1168,27 +1002,27 @@ static SecurityClass::flags_t squeeze_acl(UCHAR* acl_base,
|
||||
{
|
||||
hit = false;
|
||||
// Seems strange with the same increment just after the switch.
|
||||
acl += *acl + 1;
|
||||
a += *a + 1;
|
||||
}
|
||||
break;
|
||||
|
||||
case id_group:
|
||||
if (user_type != obj_user_group)
|
||||
hit = false;
|
||||
if (check_string(acl, user))
|
||||
if (check_string(a, user))
|
||||
hit = false;
|
||||
break;
|
||||
|
||||
default:
|
||||
BUGCHECK(293); /* bad ACL */
|
||||
}
|
||||
acl += *acl + 1;
|
||||
a += *a + 1;
|
||||
}
|
||||
break;
|
||||
|
||||
case ACL_priv_list:
|
||||
if (hit) {
|
||||
while ( (c = *acl++) )
|
||||
while ( (c = *a++) )
|
||||
switch (c) {
|
||||
case priv_control:
|
||||
privilege |= SCL_control;
|
||||
@ -1238,21 +1072,20 @@ static SecurityClass::flags_t squeeze_acl(UCHAR* acl_base,
|
||||
BUGCHECK(293); /* bad ACL */
|
||||
}
|
||||
/* Squeeze out duplicate acl element. */
|
||||
UCHAR* dest = dup_acl;
|
||||
const UCHAR* source = acl;
|
||||
int length = *acl_ptr - source + 1; // ptrdiff_t
|
||||
*acl_ptr = *acl_ptr - (source - dest);
|
||||
acl = dup_acl;
|
||||
for (; length; *dest++ = *source++, length--);
|
||||
acl.remove(dup_acl, a);
|
||||
a = dup_acl;
|
||||
}
|
||||
else
|
||||
while (*acl++);
|
||||
while (*a++);
|
||||
break;
|
||||
|
||||
default:
|
||||
BUGCHECK(293); /* bad ACL */
|
||||
}
|
||||
|
||||
// remove added extra '\0' byte
|
||||
acl.pop();
|
||||
|
||||
return privilege;
|
||||
}
|
||||
|
||||
|
@ -29,7 +29,6 @@
|
||||
class Jrd::DeferredWork;
|
||||
|
||||
bool GRANT_privileges(Jrd::thread_db*, SSHORT, Jrd::DeferredWork*, Jrd::jrd_tra*);
|
||||
void GRANT_realloc_acl(Firebird::UCharBuffer&, UCHAR**, ULONG *);
|
||||
|
||||
#endif // JRD_GRANT_PROTO_H
|
||||
|
||||
|
116
src/jrd/scl.epp
116
src/jrd/scl.epp
@ -67,28 +67,22 @@
|
||||
|
||||
const int UIC_BASE = 10;
|
||||
|
||||
const SLONG BLOB_BUFFER_SIZE = 4096; /* used to read in acl blob */
|
||||
|
||||
using namespace Jrd;
|
||||
|
||||
DATABASE DB = FILENAME "ODS.RDB";
|
||||
|
||||
static bool check_hex(const UCHAR*, USHORT);
|
||||
static bool check_number(const UCHAR*, USHORT);
|
||||
static bool check_user_group(const UCHAR*, USHORT, const ULONG);
|
||||
static bool check_user_group(const UCHAR*, USHORT);
|
||||
static bool check_string(const UCHAR*, const Firebird::MetaName&);
|
||||
static SecurityClass::flags_t compute_access(thread_db*, const SecurityClass*,
|
||||
const jrd_rel*, const Firebird::MetaName&, const Firebird::MetaName&);
|
||||
static SecurityClass::flags_t walk_acl(thread_db*, const UCHAR*, const jrd_rel*,
|
||||
const Firebird::MetaName&, const Firebird::MetaName&, const ULONG);
|
||||
static SecurityClass::flags_t walk_acl(thread_db*, const Acl&, const jrd_rel*,
|
||||
const Firebird::MetaName&, const Firebird::MetaName&);
|
||||
|
||||
static inline void check_and_move(UCHAR*& to, UCHAR from, Firebird::UCharBuffer& start, ULONG* length_ptr)
|
||||
static inline void check_and_move(UCHAR from, Acl& to)
|
||||
{
|
||||
if ((start.begin() + *length_ptr) < (to + 1))
|
||||
{
|
||||
GRANT_realloc_acl(start, &to, length_ptr);
|
||||
}
|
||||
*to++ = from;
|
||||
to.push(from);
|
||||
}
|
||||
|
||||
struct P_NAMES {
|
||||
@ -768,8 +762,7 @@ void SCL_init(bool create,
|
||||
}
|
||||
|
||||
|
||||
void SCL_move_priv(UCHAR** acl_ptr, SecurityClass::flags_t mask,
|
||||
Firebird::UCharBuffer& start_ptr, ULONG* length_ptr)
|
||||
void SCL_move_priv(SecurityClass::flags_t mask, Acl& acl)
|
||||
{
|
||||
/**************************************
|
||||
*
|
||||
@ -781,25 +774,21 @@ void SCL_move_priv(UCHAR** acl_ptr, SecurityClass::flags_t mask,
|
||||
* Given a mask of privileges, move privileges types to acl.
|
||||
*
|
||||
**************************************/
|
||||
UCHAR* p = *acl_ptr;
|
||||
|
||||
// Terminate identification criteria, and move privileges
|
||||
|
||||
check_and_move(p, ACL_end, start_ptr, length_ptr);
|
||||
check_and_move(p, ACL_priv_list, start_ptr, length_ptr);
|
||||
check_and_move(ACL_end, acl);
|
||||
check_and_move(ACL_priv_list, acl);
|
||||
|
||||
for (const P_NAMES* priv = p_names; priv->p_names_priv; priv++)
|
||||
{
|
||||
if (mask & priv->p_names_priv)
|
||||
{
|
||||
fb_assert(priv->p_names_acl <= MAX_UCHAR);
|
||||
check_and_move(p, priv->p_names_acl, start_ptr, length_ptr);
|
||||
check_and_move(priv->p_names_acl, acl);
|
||||
}
|
||||
}
|
||||
|
||||
check_and_move(p, 0, start_ptr, length_ptr);
|
||||
|
||||
*acl_ptr = p;
|
||||
check_and_move(0, acl);
|
||||
}
|
||||
|
||||
|
||||
@ -934,8 +923,7 @@ static bool check_number(const UCHAR* acl, USHORT number)
|
||||
|
||||
|
||||
static bool check_user_group(const UCHAR* acl,
|
||||
USHORT number,
|
||||
const ULONG length)
|
||||
USHORT number)
|
||||
{
|
||||
/**************************************
|
||||
*
|
||||
@ -975,19 +963,14 @@ static bool check_user_group(const UCHAR* acl,
|
||||
}
|
||||
else // processing group name
|
||||
{
|
||||
Firebird::UCharBuffer buffer;
|
||||
fb_assert(l < length); // Not sure how we can guarantee this.
|
||||
UCHAR* user_group_name = buffer.getBuffer(length);
|
||||
Firebird::string user_group_name;
|
||||
do {
|
||||
const TEXT one_char = *acl++;
|
||||
*user_group_name++ = LOWWER(one_char);
|
||||
user_group_name += LOWWER(one_char);
|
||||
} while (--l);
|
||||
*user_group_name = '\0';
|
||||
user_group_name = buffer.begin();
|
||||
|
||||
// convert unix group name to unix group id
|
||||
|
||||
n = ISC_get_user_group_id(reinterpret_cast<const TEXT*>(user_group_name));
|
||||
n = ISC_get_user_group_id(user_group_name.c_str());
|
||||
}
|
||||
}
|
||||
|
||||
@ -1035,10 +1018,7 @@ static SecurityClass::flags_t compute_access(thread_db* tdbb,
|
||||
* access permissions. Return a flag word of recognized privileges.
|
||||
*
|
||||
**************************************/
|
||||
Firebird::UCharBuffer str_buffer;
|
||||
UCHAR* buffer = str_buffer.getBuffer(BLOB_BUFFER_SIZE);
|
||||
|
||||
SLONG length = BLOB_BUFFER_SIZE;
|
||||
Acl acl;
|
||||
|
||||
SET_TDBB(tdbb);
|
||||
Database* dbb = tdbb->getDatabase();
|
||||
@ -1055,13 +1035,11 @@ static SecurityClass::flags_t compute_access(thread_db* tdbb,
|
||||
|
||||
privileges |= SCL_exists;
|
||||
blb* blob = BLB_open(tdbb, dbb->dbb_sys_trans, &X.RDB$ACL);
|
||||
UCHAR* acl = buffer;
|
||||
UCHAR* buffer = acl.getBuffer(ACL_BLOB_BUFFER_SIZE);
|
||||
UCHAR* end = buffer;
|
||||
while (true)
|
||||
{
|
||||
acl += BLB_get_segment(tdbb, blob, acl,
|
||||
(USHORT) (length -
|
||||
((acl - buffer) *
|
||||
(sizeof(buffer[0])))));
|
||||
end += BLB_get_segment(tdbb, blob, end, (USHORT) (acl.getCount() - (end - buffer)) );
|
||||
if (blob->blb_flags & BLB_eof)
|
||||
break;
|
||||
|
||||
@ -1069,22 +1047,21 @@ static SecurityClass::flags_t compute_access(thread_db* tdbb,
|
||||
|
||||
if (blob->blb_fragment_size)
|
||||
{
|
||||
const ULONG old_offset = (ULONG) (acl - buffer);
|
||||
length += BLOB_BUFFER_SIZE;
|
||||
buffer = str_buffer.getBuffer(length);
|
||||
acl = buffer + old_offset;
|
||||
const ptrdiff_t old_offset = end - buffer;
|
||||
buffer = acl.getBuffer(acl.getCount() + ACL_BLOB_BUFFER_SIZE);
|
||||
end = buffer + old_offset;
|
||||
}
|
||||
}
|
||||
BLB_close(tdbb, blob);
|
||||
blob = NULL;
|
||||
if (acl != buffer)
|
||||
acl.shrink(end - buffer);
|
||||
if (acl.getCount() > 0)
|
||||
{
|
||||
privileges |= walk_acl( tdbb,
|
||||
buffer,
|
||||
acl,
|
||||
view,
|
||||
trg_name,
|
||||
prc_name,
|
||||
length);
|
||||
prc_name);
|
||||
}
|
||||
END_FOR;
|
||||
|
||||
@ -1096,11 +1073,10 @@ static SecurityClass::flags_t compute_access(thread_db* tdbb,
|
||||
|
||||
|
||||
static SecurityClass::flags_t walk_acl(thread_db* tdbb,
|
||||
const UCHAR* acl,
|
||||
const Acl& acl,
|
||||
const jrd_rel* view,
|
||||
const Firebird::MetaName& trg_name,
|
||||
const Firebird::MetaName& prc_name,
|
||||
const ULONG length)
|
||||
const Firebird::MetaName& prc_name)
|
||||
{
|
||||
/**************************************
|
||||
*
|
||||
@ -1131,9 +1107,11 @@ static SecurityClass::flags_t walk_acl(thread_db* tdbb,
|
||||
|
||||
user.usr_user_name = view->rel_owner_name.c_str();
|
||||
}
|
||||
SecurityClass::flags_t privilege = 0;
|
||||
|
||||
if (*acl++ != ACL_version)
|
||||
SecurityClass::flags_t privilege = 0;
|
||||
const UCHAR* a = acl.begin();
|
||||
|
||||
if (*a++ != ACL_version)
|
||||
{
|
||||
BUGCHECK(160); // msg 160 wrong ACL version
|
||||
}
|
||||
@ -1147,42 +1125,40 @@ static SecurityClass::flags_t walk_acl(thread_db* tdbb,
|
||||
bool hit = false;
|
||||
UCHAR c;
|
||||
|
||||
while ( (c = *acl++) )
|
||||
while ( (c = *a++) )
|
||||
{
|
||||
switch (c)
|
||||
{
|
||||
case ACL_id_list:
|
||||
hit = true;
|
||||
while ( (c = *acl++) )
|
||||
while ( (c = *a++) )
|
||||
{
|
||||
switch (c)
|
||||
{
|
||||
case id_person:
|
||||
if (!(p = user.usr_user_name.nullStr()) || check_string(acl, p))
|
||||
if (!(p = user.usr_user_name.nullStr()) || check_string(a, p))
|
||||
hit = false;
|
||||
break;
|
||||
|
||||
case id_project:
|
||||
if (!(p = user.usr_project_name.nullStr()) || check_string(acl, p))
|
||||
if (!(p = user.usr_project_name.nullStr()) || check_string(a, p))
|
||||
hit = false;
|
||||
break;
|
||||
|
||||
case id_organization:
|
||||
if (!(p = user.usr_org_name.nullStr()) || check_string(acl, p))
|
||||
if (!(p = user.usr_org_name.nullStr()) || check_string(a, p))
|
||||
hit = false;
|
||||
break;
|
||||
|
||||
case id_group:
|
||||
if (check_user_group(acl,
|
||||
user.usr_group_id,
|
||||
length))
|
||||
if (check_user_group(a, user.usr_group_id))
|
||||
{
|
||||
hit = false;
|
||||
}
|
||||
break;
|
||||
|
||||
case id_sql_role:
|
||||
if (!role_name || check_string(acl, role_name))
|
||||
if (!role_name || check_string(a, role_name))
|
||||
hit = false;
|
||||
else
|
||||
{
|
||||
@ -1218,17 +1194,17 @@ static SecurityClass::flags_t walk_acl(thread_db* tdbb,
|
||||
break;
|
||||
|
||||
case id_view:
|
||||
if (!view || check_string(acl, view->rel_name))
|
||||
if (!view || check_string(a, view->rel_name))
|
||||
hit = false;
|
||||
break;
|
||||
|
||||
case id_procedure:
|
||||
if (check_string(acl, prc_name))
|
||||
if (check_string(a, prc_name))
|
||||
hit = false;
|
||||
break;
|
||||
|
||||
case id_trigger:
|
||||
if (check_string(acl, trg_name))
|
||||
if (check_string(a, trg_name))
|
||||
{
|
||||
hit = false;
|
||||
}
|
||||
@ -1247,13 +1223,13 @@ static SecurityClass::flags_t walk_acl(thread_db* tdbb,
|
||||
break;
|
||||
|
||||
case id_user:
|
||||
if (check_number(acl, user.usr_user_id)) {
|
||||
if (check_number(a, user.usr_user_id)) {
|
||||
hit = false;
|
||||
}
|
||||
break;
|
||||
|
||||
case id_node:
|
||||
if (check_hex(acl, user.usr_node_id)) {
|
||||
if (check_hex(a, user.usr_node_id)) {
|
||||
hit = false;
|
||||
}
|
||||
break;
|
||||
@ -1261,13 +1237,13 @@ static SecurityClass::flags_t walk_acl(thread_db* tdbb,
|
||||
default:
|
||||
return SCL_corrupt;
|
||||
}
|
||||
acl += *acl + 1;
|
||||
a += *a + 1;
|
||||
}
|
||||
break;
|
||||
|
||||
case ACL_priv_list:
|
||||
if (hit) {
|
||||
while ( (c = *acl++) )
|
||||
while ( (c = *a++) )
|
||||
switch (c) {
|
||||
case priv_control:
|
||||
privilege |= SCL_control;
|
||||
@ -1330,7 +1306,7 @@ static SecurityClass::flags_t walk_acl(thread_db* tdbb,
|
||||
// -- Madhukar Thakur (May 1, 1995)
|
||||
}
|
||||
else
|
||||
while (*acl++);
|
||||
while (*a++);
|
||||
break;
|
||||
|
||||
default:
|
||||
|
@ -29,6 +29,8 @@
|
||||
|
||||
namespace Jrd {
|
||||
|
||||
const size_t ACL_BLOB_BUFFER_SIZE = 4096; /* used to read/write acl blob */
|
||||
|
||||
// Security class definition
|
||||
|
||||
class SecurityClass
|
||||
|
@ -66,9 +66,14 @@ void SCL_check_relation(const dsc*, Jrd::SecurityClass::flags_t);
|
||||
Jrd::SecurityClass* SCL_get_class(Jrd::thread_db*, const TEXT*);
|
||||
Jrd::SecurityClass::flags_t SCL_get_mask(const TEXT*, const TEXT*);
|
||||
void SCL_init(bool, const Jrd::UserId& tempId, Jrd::thread_db*);
|
||||
void SCL_move_priv(UCHAR**, Jrd::SecurityClass::flags_t, Firebird::UCharBuffer&, ULONG*);
|
||||
Jrd::SecurityClass* SCL_recompute_class(Jrd::thread_db*, const TEXT*);
|
||||
void SCL_release_all(Jrd::SecurityClassList*&);
|
||||
|
||||
namespace Jrd {
|
||||
typedef Firebird::Array<UCHAR> Acl;
|
||||
}
|
||||
void SCL_move_priv(Jrd::SecurityClass::flags_t, Jrd::Acl&);
|
||||
|
||||
|
||||
#endif // JRD_SCL_PROTO_H
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user