bool checkCreateDatabaseGrant(const MetaName& userName, const MetaName& trustedRole, const MetaName& sqlRole, const char* securityDb) { if (userName == SYSDBA_USER_NAME) return true; RefPtr<IAttachment> att; RefPtr<ITransaction> tra; if (!openDb(securityDb, att, tra)) return false; FbLocalStatus st; MetaName role(sqlRole); if (role.hasData()) { const UCHAR info[] = { isc_info_db_sql_dialect, isc_info_end }; UCHAR buffer[BUFFER_TINY]; att->getInfo(&st, sizeof(info), info, sizeof(buffer), buffer); check("IAttachment::getInfo", &st); int dialect = SQL_DIALECT_V5; // reasonable default const UCHAR* p = buffer; while (*p != isc_info_end && *p != isc_info_truncated && p < buffer + sizeof(buffer)) { const UCHAR item = (UCHAR) *p++; const USHORT length = gds__vax_integer(p, sizeof(USHORT)); p += sizeof(USHORT); switch (item) { case isc_info_db_sql_dialect: dialect = gds__vax_integer(p, length); break; } p += length; } JRD_make_role_name(role, dialect); // We need to check is admin role granted to userName in security DB const char* sql = "select count(*) from RDB$USER_PRIVILEGES " "where RDB$USER = ? and RDB$RELATION_NAME = ? and RDB$PRIVILEGE = 'M'"; Message prm; Field<Varying> u(prm, MAX_SQL_IDENTIFIER_LEN); Field<Varying> r(prm, MAX_SQL_IDENTIFIER_LEN); u = userName.c_str(); r = role.c_str(); Message result; Field<ISC_INT64> cnt(result); att->execute(&st, tra, 0, sql, SQL_DIALECT_V6, prm.getMetadata(), prm.getBuffer(), result.getMetadata(), result.getBuffer()); if (st->getState() & IStatus::STATE_ERRORS) { // isc_dsql_relation_err when exec SQL - i.e. table RDB$USER_PRIVILEGES // is missing due to non-FB security DB if (!fb_utils::containsErrorCode(st->getErrors(), isc_dsql_relation_err)) check("IAttachment::execute", &st); role = ""; } else if (cnt == 0) role = ""; } else role = trustedRole; if (role == ADMIN_ROLE) return true; Message gr; Field<ISC_SHORT> uType(gr); Field<Varying> u(gr, MAX_SQL_IDENTIFIER_LEN); Field<ISC_SHORT> rType(gr); Field<Varying> r(gr, MAX_SQL_IDENTIFIER_LEN); uType = obj_user; u = userName.c_str(); rType = role.hasData() ? obj_sql_role : 255; r = role.c_str(); Message result; Field<ISC_INT64> cnt(result); att->execute(&st, tra, 0, "select count(*) from RDB$DB_CREATORS" " where (RDB$USER_TYPE = ? and RDB$USER = ?) or (RDB$USER_TYPE = ? and RDB$USER = ?)", SQL_DIALECT_V6, gr.getMetadata(), gr.getBuffer(), result.getMetadata(), result.getBuffer()); if (st->getState() & IStatus::STATE_ERRORS) { if (fb_utils::containsErrorCode(st->getErrors(), isc_dsql_relation_err)) { // isc_dsql_relation_err when exec SQL - i.e. table RDB$DB_CREATORS // is missing due to non-FB3 security DB return false; } check("IAttachment::execute", &st); } return cnt > 0; }
RecordBuffer* DbCreatorsList::getList(thread_db* tdbb, jrd_rel* relation) { fb_assert(relation); fb_assert(relation->rel_id == rel_sec_db_creators); RecordBuffer* buffer = getData(relation); if (buffer) { return buffer; } RefPtr<IAttachment> att; RefPtr<ITransaction> tra; const char* dbName = tdbb->getDatabase()->dbb_config->getSecurityDatabase(); if (!openDb(dbName, att, tra)) { // In embedded mode we are not raising any errors - silent return if (MasterInterfacePtr()->serverMode(-1) < 0) return makeBuffer(tdbb); (Arg::Gds(isc_crdb_nodb) << dbName).raise(); } Message gr; Field<ISC_SHORT> uType(gr); Field<Varying> u(gr, MAX_SQL_IDENTIFIER_LEN); FbLocalStatus st; RefPtr<IResultSet> curs(att->openCursor(&st, tra, 0, "select RDB$USER_TYPE, RDB$USER from RDB$DB_CREATORS", SQL_DIALECT_V6, NULL, NULL, gr.getMetadata(), NULL, 0)); if (st->getState() & IStatus::STATE_ERRORS) { if (!fb_utils::containsErrorCode(st->getErrors(), isc_dsql_relation_err)) check("IAttachment::openCursor", &st); // isc_dsql_relation_err when opening cursor - i.e. table // is missing due to non-FB3 security DB // In embedded mode we are not raising any errors - silent return if (MasterInterfacePtr()->serverMode(-1) < 0) return makeBuffer(tdbb); (Arg::Gds(isc_crdb_notable) << dbName).raise(); } try { buffer = makeBuffer(tdbb); while (curs->fetchNext(&st, gr.getBuffer()) == IStatus::RESULT_OK) { Record* record = buffer->getTempRecord(); record->nullify(); putField(tdbb, record, DumpField(f_sec_crt_user, VALUE_STRING, u->len, u->data)); SINT64 v = uType; putField(tdbb, record, DumpField(f_sec_crt_u_type, VALUE_INTEGER, sizeof(v), &v)); buffer->store(record); } check("IResultSet::fetchNext", &st); } catch (const Exception&) { clearSnapshot(); throw; } return getData(relation); }
bool checkCreateDatabaseGrant(const MetaName& userName, const MetaName& trustedRole, const MetaName& sqlRole, const char* securityDb) { if (userName == DBA_USER_NAME) return true; RefPtr<IAttachment> att; RefPtr<ITransaction> tra; bool hasDb = openDb(securityDb, att, tra); FbLocalStatus st; MetaName role(sqlRole); if (hasDb && role.hasData()) { const UCHAR info[] = { isc_info_db_sql_dialect, isc_info_end }; UCHAR buffer[BUFFER_TINY]; att->getInfo(&st, sizeof(info), info, sizeof(buffer), buffer); check("IAttachment::getInfo", &st); int dialect = SQL_DIALECT_V5; // reasonable default const UCHAR* p = buffer; while (*p != isc_info_end && *p != isc_info_truncated && p < buffer + sizeof(buffer)) { const UCHAR item = (UCHAR) *p++; const USHORT length = gds__vax_integer(p, sizeof(USHORT)); p += sizeof(USHORT); switch (item) { case isc_info_db_sql_dialect: dialect = gds__vax_integer(p, length); break; } p += length; } UserId::makeRoleName(role, dialect); // We need to check is role granted to userName in security DB const char* sql = "select count(*) from RDB$USER_PRIVILEGES " "where RDB$USER = ? and RDB$RELATION_NAME = ? and RDB$PRIVILEGE = 'M'"; Message prm; Field<Varying> u(prm, MAX_SQL_IDENTIFIER_LEN); Field<Varying> r(prm, MAX_SQL_IDENTIFIER_LEN); u = userName.c_str(); r = role.c_str(); Message result; Field<ISC_INT64> cnt(result); att->execute(&st, tra, 0, sql, SQL_DIALECT_V6, prm.getMetadata(), prm.getBuffer(), result.getMetadata(), result.getBuffer()); if (st->getState() & IStatus::STATE_ERRORS) { // isc_dsql_relation_err when exec SQL - i.e. table RDB$USER_PRIVILEGES // is missing due to non-FB security DB if (!fb_utils::containsErrorCode(st->getErrors(), isc_dsql_relation_err)) check("IAttachment::execute", &st); role = ""; } else if (cnt == 0) role = ""; } else role = trustedRole; if (role == ADMIN_ROLE) return true; if (!hasDb) return false; // check db creators table Message gr; Field<ISC_SHORT> uType(gr); Field<Varying> u(gr, MAX_SQL_IDENTIFIER_LEN); Field<ISC_SHORT> rType(gr); Field<Varying> r(gr, MAX_SQL_IDENTIFIER_LEN); uType = obj_user; u = userName.c_str(); rType = role.hasData() ? obj_sql_role : 255; r = role.c_str(); Message result; Field<ISC_INT64> cnt(result); att->execute(&st, tra, 0, "select count(*) from RDB$DB_CREATORS" " where (RDB$USER_TYPE = ? and RDB$USER = ?) or (RDB$USER_TYPE = ? and RDB$USER = ?)", SQL_DIALECT_V6, gr.getMetadata(), gr.getBuffer(), result.getMetadata(), result.getBuffer()); if (st->getState() & IStatus::STATE_ERRORS) { if (fb_utils::containsErrorCode(st->getErrors(), isc_dsql_relation_err)) { // isc_dsql_relation_err when exec SQL - i.e. table RDB$DB_CREATORS // is missing due to non-FB3 security DB return false; } check("IAttachment::execute", &st); } if (cnt > 0) return true; if (!role.hasData()) role = "NONE"; Message par2; Field<ISC_SHORT> uType2(par2); Field<Varying> u2(par2, MAX_SQL_IDENTIFIER_LEN); Field<Varying> r2(par2, MAX_SQL_IDENTIFIER_LEN); uType2 = obj_user; u2 = userName.c_str(); r2 = role.c_str(); Message res2; Field<Text> priv(res2, 8); const char* sql = "with recursive role_tree as ( " " select rdb$relation_name as nm, 0 as ur from rdb$user_privileges " " where rdb$privilege = 'M' and rdb$field_name = 'D' and rdb$user_type = ? and rdb$user = ? " " union all " " select rdb$role_name as nm, 1 as ur from rdb$roles " " where rdb$role_name = ? " " union all " " select p.rdb$relation_name as nm, t.ur from rdb$user_privileges p " " join role_tree t on t.nm = p.rdb$user " " where p.rdb$privilege = 'M' and (p.rdb$field_name = 'D' or t.ur = 1)) " "select r.rdb$system_privileges " " from role_tree t join rdb$roles r on t.nm = r.rdb$role_name "; RefPtr<IResultSet> rs(REF_NO_INCR, att->openCursor(&st, tra, 0, sql, SQL_DIALECT_V6, par2.getMetadata(), par2.getBuffer(), res2.getMetadata(), NULL, 0)); check("IAttachment::execute", &st); UserId::Privileges privileges, wrk; while (rs->fetchNext(&st, res2.getBuffer()) == IStatus::RESULT_OK) { wrk.load(&priv); privileges |= wrk; } check("IResultSet::fetchNext", &st); return wrk.test(CREATE_DATABASE); }