From: <ale...@us...> - 2014-04-30 15:12:16
|
Revision: 59508 http://sourceforge.net/p/firebird/code/59508 Author: alexpeshkoff Date: 2014-04-30 15:12:12 +0000 (Wed, 30 Apr 2014) Log Message: ----------- Implemented CORE-1377: Add an ability to change role without reconnecting to database Modified Paths: -------------- firebird/trunk/lang_helpers/gds_codes.ftn firebird/trunk/lang_helpers/gds_codes.pas firebird/trunk/src/dsql/StmtNodes.cpp firebird/trunk/src/dsql/StmtNodes.h firebird/trunk/src/dsql/dsql.cpp firebird/trunk/src/dsql/dsql.h firebird/trunk/src/dsql/parse.y firebird/trunk/src/include/gen/codetext.h firebird/trunk/src/include/gen/iberror.h firebird/trunk/src/include/gen/msgs.h firebird/trunk/src/include/gen/sql_code.h firebird/trunk/src/include/gen/sql_state.h firebird/trunk/src/isql/isql.epp firebird/trunk/src/jrd/irq.h firebird/trunk/src/jrd/jrd.cpp firebird/trunk/src/jrd/scl.epp firebird/trunk/src/jrd/scl.h firebird/trunk/src/jrd/scl_proto.h firebird/trunk/src/msgs/facilities2.sql firebird/trunk/src/msgs/messages2.sql firebird/trunk/src/msgs/system_errors2.sql firebird/trunk/src/yvalve/keywords.cpp Modified: firebird/trunk/lang_helpers/gds_codes.ftn =================================================================== --- firebird/trunk/lang_helpers/gds_codes.ftn 2014-04-30 12:20:59 UTC (rev 59507) +++ firebird/trunk/lang_helpers/gds_codes.ftn 2014-04-30 15:12:12 UTC (rev 59508) @@ -1590,6 +1590,10 @@ PARAMETER (GDS__map_nodb = 335545088) INTEGER*4 GDS__map_notable PARAMETER (GDS__map_notable = 335545089) + INTEGER*4 GDS__miss_trusted_role + PARAMETER (GDS__miss_trusted_role = 335545090) + INTEGER*4 GDS__set_invalid_role + PARAMETER (GDS__set_invalid_role = 335545091) INTEGER*4 GDS__gfix_db_name PARAMETER (GDS__gfix_db_name = 335740929) INTEGER*4 GDS__gfix_invalid_sw Modified: firebird/trunk/lang_helpers/gds_codes.pas =================================================================== --- firebird/trunk/lang_helpers/gds_codes.pas 2014-04-30 12:20:59 UTC (rev 59507) +++ firebird/trunk/lang_helpers/gds_codes.pas 2014-04-30 15:12:12 UTC (rev 59508) @@ -802,6 +802,8 @@ gds_baddpb_temp_buffers = 335545087; gds_map_nodb = 335545088; gds_map_notable = 335545089; + gds_miss_trusted_role = 335545090; + gds_set_invalid_role = 335545091; gds_gfix_db_name = 335740929; gds_gfix_invalid_sw = 335740930; gds_gfix_incmp_sw = 335740932; Modified: firebird/trunk/src/dsql/StmtNodes.cpp =================================================================== --- firebird/trunk/src/dsql/StmtNodes.cpp 2014-04-30 12:20:59 UTC (rev 59507) +++ firebird/trunk/src/dsql/StmtNodes.cpp 2014-04-30 15:12:12 UTC (rev 59508) @@ -49,6 +49,7 @@ #include "../jrd/par_proto.h" #include "../jrd/rlck_proto.h" #include "../jrd/tra_proto.h" +#include "../jrd/scl_proto.h" #include "../dsql/ddl_proto.h" #include "../dsql/metd_proto.h" #include "../jrd/vio_proto.h" @@ -7593,6 +7594,45 @@ //-------------------- +SetRoleNode* SetRoleNode::dsqlPass(DsqlCompilerScratch* dsqlScratch) +{ + dsqlScratch->getStatement()->setType(DsqlCompiledStatement::TYPE_SET_ROLE); + + return this; +} + +void SetRoleNode::execute(thread_db* tdbb, dsql_req* request, jrd_tra** transaction) const +{ + SET_TDBB(tdbb); + Attachment* const attachment = tdbb->getAttachment(); + UserId* user = attachment->att_user; + fb_assert(user); + + if (trusted) + { + if (!user->usr_trusted_role.hasData()) + Arg::Gds(isc_miss_trusted_role).raise(); + user->usr_sql_role_name = user->usr_trusted_role; + } + else + { + if (!SCL_role_granted(tdbb, *user, roleName.c_str())) + (Arg::Gds(isc_set_invalid_role) << roleName).raise(); + user->usr_sql_role_name = roleName.c_str(); + } + + if (SCL_admin_role(tdbb, user->usr_sql_role_name.c_str())) + user->usr_flags |= USR_dba; + else + user->usr_flags &= ~USR_dba; + + SCL_release_all(attachment->att_security_classes); +} + + +//-------------------- + + StmtNode* UpdateOrInsertNode::dsqlPass(DsqlCompilerScratch* dsqlScratch) { thread_db* tdbb = JRD_get_thread_data(); // necessary? Modified: firebird/trunk/src/dsql/StmtNodes.h =================================================================== --- firebird/trunk/src/dsql/StmtNodes.h 2014-04-30 12:20:59 UTC (rev 59507) +++ firebird/trunk/src/dsql/StmtNodes.h 2014-04-30 15:12:12 UTC (rev 59508) @@ -1509,6 +1509,42 @@ }; +// This node should better be session management node, +// but as long as we do not have other session management and +// node is rather similiar internally to transaction management +// let it for now be transaction management node. +class SetRoleNode : public TransactionNode +{ +public: + explicit SetRoleNode(MemoryPool& pool) + : TransactionNode(pool), + trusted(true), + roleName(pool) + { + } + + SetRoleNode(MemoryPool& pool, Firebird::MetaName* name) + : TransactionNode(pool), + trusted(false), + roleName(pool, *name) + { + } + +public: + virtual void print(Firebird::string& text) const + { + text = "SetRoleNode"; + } + + virtual SetRoleNode* dsqlPass(DsqlCompilerScratch* dsqlScratch); + virtual void execute(thread_db* tdbb, dsql_req* request, jrd_tra** transaction) const; + +public: + bool trusted; + Firebird::MetaName roleName; +}; + + class UpdateOrInsertNode : public TypedNode<DsqlOnlyStmtNode, StmtNode::TYPE_UPDATE_OR_INSERT> { public: Modified: firebird/trunk/src/dsql/dsql.cpp =================================================================== --- firebird/trunk/src/dsql/dsql.cpp 2014-04-30 12:20:59 UTC (rev 59507) +++ firebird/trunk/src/dsql/dsql.cpp 2014-04-30 15:12:12 UTC (rev 59508) @@ -1822,6 +1822,7 @@ break; case DsqlCompiledStatement::TYPE_CREATE_DB: case DsqlCompiledStatement::TYPE_DDL: + case DsqlCompiledStatement::TYPE_SET_ROLE: number = isc_info_sql_stmt_ddl; break; case DsqlCompiledStatement::TYPE_COMMIT: Modified: firebird/trunk/src/dsql/dsql.h =================================================================== --- firebird/trunk/src/dsql/dsql.h 2014-04-30 12:20:59 UTC (rev 59507) +++ firebird/trunk/src/dsql/dsql.h 2014-04-30 15:12:12 UTC (rev 59508) @@ -429,7 +429,7 @@ TYPE_SELECT, TYPE_SELECT_UPD, TYPE_INSERT, TYPE_DELETE, TYPE_UPDATE, TYPE_UPDATE_CURSOR, TYPE_DELETE_CURSOR, TYPE_COMMIT, TYPE_ROLLBACK, TYPE_CREATE_DB, TYPE_DDL, TYPE_START_TRANS, TYPE_EXEC_PROCEDURE, TYPE_COMMIT_RETAIN, TYPE_ROLLBACK_RETAIN, TYPE_SET_GENERATOR, - TYPE_SAVEPOINT, TYPE_EXEC_BLOCK, TYPE_SELECT_BLOCK + TYPE_SAVEPOINT, TYPE_EXEC_BLOCK, TYPE_SELECT_BLOCK, TYPE_SET_ROLE }; // Statement flags. Modified: firebird/trunk/src/dsql/parse.y =================================================================== --- firebird/trunk/src/dsql/parse.y 2014-04-30 12:20:59 UTC (rev 59507) +++ firebird/trunk/src/dsql/parse.y 2014-04-30 15:12:12 UTC (rev 59508) @@ -569,6 +569,7 @@ %token <metaNamePtr> PLUGIN %token <metaNamePtr> SERVERWIDE %token <metaNamePtr> INCREMENT +%token <metaNamePtr> TRUSTED // precedence declarations for expression evaluation @@ -697,6 +698,7 @@ Jrd::CreateAlterUserNode* createAlterUserNode; Jrd::MappingNode* mappingNode; Jrd::MappingNode::OP mappingOp; + Jrd::SetRoleNode* setRoleNode; } %include types.y @@ -749,6 +751,7 @@ : set_transaction { $$ = $1; } | commit { $$ = $1; } | rollback { $$ = $1; } + | set_role { $$ = $1; } ; @@ -4468,6 +4471,14 @@ { $$ = $3; } ; +%type <setRoleNode> set_role +set_role + : SET ROLE valid_symbol_name + { $$ = newNode<SetRoleNode>($3); } + | SET TRUSTED ROLE + { $$ = newNode<SetRoleNode>(); } + ; + %type tran_option_list_opt(<setTransactionNode>) tran_option_list_opt($setTransactionNode) : // nothing @@ -7373,6 +7384,7 @@ | PLUGIN | SERVERWIDE | INCREMENT + | TRUSTED ; %% Modified: firebird/trunk/src/include/gen/codetext.h =================================================================== --- firebird/trunk/src/include/gen/codetext.h 2014-04-30 12:20:59 UTC (rev 59507) +++ firebird/trunk/src/include/gen/codetext.h 2014-04-30 15:12:12 UTC (rev 59508) @@ -791,6 +791,8 @@ {"baddpb_temp_buffers", 335545087}, {"map_nodb", 335545088}, {"map_notable", 335545089}, + {"miss_trusted_role", 335545090}, + {"set_invalid_role", 335545091}, {"gfix_db_name", 335740929}, {"gfix_invalid_sw", 335740930}, {"gfix_incmp_sw", 335740932}, Modified: firebird/trunk/src/include/gen/iberror.h =================================================================== --- firebird/trunk/src/include/gen/iberror.h 2014-04-30 12:20:59 UTC (rev 59507) +++ firebird/trunk/src/include/gen/iberror.h 2014-04-30 15:12:12 UTC (rev 59508) @@ -825,6 +825,8 @@ const ISC_STATUS isc_baddpb_temp_buffers = 335545087L; const ISC_STATUS isc_map_nodb = 335545088L; const ISC_STATUS isc_map_notable = 335545089L; +const ISC_STATUS isc_miss_trusted_role = 335545090L; +const ISC_STATUS isc_set_invalid_role = 335545091L; const ISC_STATUS isc_gfix_db_name = 335740929L; const ISC_STATUS isc_gfix_invalid_sw = 335740930L; const ISC_STATUS isc_gfix_incmp_sw = 335740932L; @@ -1278,7 +1280,7 @@ const ISC_STATUS isc_trace_switch_param_miss = 337182758L; const ISC_STATUS isc_trace_param_act_notcompat = 337182759L; const ISC_STATUS isc_trace_mandatory_switch_miss = 337182760L; -const ISC_STATUS isc_err_max = 1222; +const ISC_STATUS isc_err_max = 1224; #else /* c definitions */ @@ -2073,6 +2075,8 @@ #define isc_baddpb_temp_buffers 335545087L #define isc_map_nodb 335545088L #define isc_map_notable 335545089L +#define isc_miss_trusted_role 335545090L +#define isc_set_invalid_role 335545091L #define isc_gfix_db_name 335740929L #define isc_gfix_invalid_sw 335740930L #define isc_gfix_incmp_sw 335740932L @@ -2526,7 +2530,7 @@ #define isc_trace_switch_param_miss 337182758L #define isc_trace_param_act_notcompat 337182759L #define isc_trace_mandatory_switch_miss 337182760L -#define isc_err_max 1222 +#define isc_err_max 1224 #endif Modified: firebird/trunk/src/include/gen/msgs.h =================================================================== --- firebird/trunk/src/include/gen/msgs.h 2014-04-30 12:20:59 UTC (rev 59507) +++ firebird/trunk/src/include/gen/msgs.h 2014-04-30 15:12:12 UTC (rev 59508) @@ -794,6 +794,8 @@ {335545087, "Attempt to temporarily set number of buffers less than @1"}, /* baddpb_temp_buffers */ {335545088, "Global mapping is not available when database @1 is not present"}, /* map_nodb */ {335545089, "Global mapping is not available when table RDB$MAP is not present in database @1"}, /* map_notable */ + {335545090, "Your attachment has no trusted role"}, /* miss_trusted_role */ + {335545091, "Role @1 is invalid or unavailable"}, /* set_invalid_role */ {335740929, "data base file name (@1) already given"}, /* gfix_db_name */ {335740930, "invalid switch @1"}, /* gfix_invalid_sw */ {335740932, "incompatible switch combination"}, /* gfix_incmp_sw */ Modified: firebird/trunk/src/include/gen/sql_code.h =================================================================== --- firebird/trunk/src/include/gen/sql_code.h 2014-04-30 12:20:59 UTC (rev 59507) +++ firebird/trunk/src/include/gen/sql_code.h 2014-04-30 15:12:12 UTC (rev 59508) @@ -790,6 +790,8 @@ {335545087, -924}, /* 767 baddpb_temp_buffers */ {335545088, -901}, /* 768 map_nodb */ {335545089, -901}, /* 769 map_notable */ + {335545090, -901}, /* 770 miss_trusted_role */ + {335545091, -901}, /* 771 set_invalid_role */ {335740929, -901}, /* 1 gfix_db_name */ {335740930, -901}, /* 2 gfix_invalid_sw */ {335740932, -901}, /* 4 gfix_incmp_sw */ Modified: firebird/trunk/src/include/gen/sql_state.h =================================================================== --- firebird/trunk/src/include/gen/sql_state.h 2014-04-30 12:20:59 UTC (rev 59507) +++ firebird/trunk/src/include/gen/sql_state.h 2014-04-30 15:12:12 UTC (rev 59508) @@ -790,6 +790,8 @@ {335545087, "HY000"}, // 767 baddpb_temp_buffers {335545088, "0A000"}, // 768 map_nodb {335545089, "0A000"}, // 769 map_notable + {335545090, "0P000"}, // 770 miss_trusted_role + {335545091, "0P000"}, // 771 set_invalid_role {335740929, "00000"}, // 1 gfix_db_name {335740930, "00000"}, // 2 gfix_invalid_sw {335740932, "00000"}, // 4 gfix_incmp_sw Modified: firebird/trunk/src/isql/isql.epp =================================================================== --- firebird/trunk/src/isql/isql.epp 2014-04-30 12:20:59 UTC (rev 59507) +++ firebird/trunk/src/isql/isql.epp 2014-04-30 15:12:12 UTC (rev 59508) @@ -4918,7 +4918,7 @@ //#ifdef DEV_BUILD sqlda_display, //#endif - sql, warning, generator, statistics, heading, bail, + sql, warning, sqlCont, heading, bail, bulk_insert, maxrows, wrong }; SetOptions(const optionsMap* inmap, size_t insize, int wrongval) @@ -4948,13 +4948,15 @@ {SetOptions::sql, "SQL", 0}, {SetOptions::warning, "WARNINGS", 7}, {SetOptions::warning, "WNG", 0}, - {SetOptions::generator, "GENERATOR", 0}, - {SetOptions::statistics, "STATISTICS", 0}, + {SetOptions::sqlCont, "GENERATOR", 0}, + {SetOptions::sqlCont, "STATISTICS", 0}, {SetOptions::heading, "HEADING", 0}, {SetOptions::bail, "BAIL", 0}, {SetOptions::bulk_insert, "BULK_INSERT", 0}, {SetOptions::maxrows, "ROWCOUNT", 0}, // legacy, compatible with FB2.5 {SetOptions::maxrows, "MAXROWS", 0}, + {SetOptions::sqlCont, "ROLE", 0}, + {SetOptions::sqlCont, "TRUSTED", 0}, // TRUSTED ROLE, will get DSQL error other case }; // Display current set options @@ -4965,6 +4967,10 @@ const SetOptions setoptions(options, FB_NELEM(options), SetOptions::wrong); switch (setoptions.getCommand(parms[1])) { + case SetOptions::sqlCont: + ret = CONT; + break; + case SetOptions::stat: ret = do_set_command(parms[2], &Stats); break; @@ -5082,11 +5088,6 @@ ret = do_set_command (parms[2], &Warnings); break; - case SetOptions::generator: - case SetOptions::statistics: - ret = CONT; - break; - case SetOptions::heading: ret = do_set_command(parms[2], &Heading); break; Modified: firebird/trunk/src/jrd/irq.h =================================================================== --- firebird/trunk/src/jrd/irq.h 2014-04-30 12:20:59 UTC (rev 59507) +++ firebird/trunk/src/jrd/irq.h 2014-04-30 15:12:12 UTC (rev 59508) @@ -103,6 +103,8 @@ irq_c_trg_perm, // check if trig can ignore perm. checks irq_get_role_mem, // get SQL role membership irq_get_role_name, // get SQL role name + irq_is_admin_role, // check is current role admin or not + irq_get_att_class, // get security class for current attachment irq_format6, // make a new format for a record irq_r_gen_id_num, // lookup generator by ID. irq_upd_gen_id_step, // update the STEP of a generator (only for legacy code). Modified: firebird/trunk/src/jrd/jrd.cpp =================================================================== --- firebird/trunk/src/jrd/jrd.cpp 2014-04-30 12:20:59 UTC (rev 59507) +++ firebird/trunk/src/jrd/jrd.cpp 2014-04-30 15:12:12 UTC (rev 59508) @@ -1223,6 +1223,87 @@ return getTransactionInterface(status, tra)->getHandle(); } +static void makeRoleName(Database* dbb, string& userIdRole, DatabaseOptions& options) +{ + if (userIdRole.hasData()) + { + switch (options.dpb_sql_dialect) + { + case 0: + // V6 Client --> V6 Server, dummy client SQL dialect 0 was passed + // It means that client SQL dialect was not set by user + // and takes DB SQL dialect as client SQL dialect + if (dbb->dbb_flags & DBB_DB_SQL_dialect_3) + { + // DB created in IB V6.0 by client SQL dialect 3 + options.dpb_sql_dialect = SQL_DIALECT_V6; + } + else + { + // old DB was gbaked in IB V6.0 + options.dpb_sql_dialect = SQL_DIALECT_V5; + } + break; + + case 99: + // V5 Client --> V6 Server, old client has no concept of dialect + options.dpb_sql_dialect = SQL_DIALECT_V5; + break; + + default: + // V6 Client --> V6 Server, but client SQL dialect was set + // by user and was passed. + break; + } + + CharSet* utf8CharSet = IntlUtil::getUtf8CharSet(); + + switch (options.dpb_sql_dialect) + { + case SQL_DIALECT_V5: + { + strip_quotes(userIdRole); + IntlUtil::toUpper(utf8CharSet, userIdRole); + } + break; + + case SQL_DIALECT_V6_TRANSITION: + case SQL_DIALECT_V6: + { + if (userIdRole.hasData() && (userIdRole[0] == DBL_QUOTE || userIdRole[0] == SINGLE_QUOTE)) + { + const char end_quote = userIdRole[0]; + // remove the delimited quotes and escape quote + // from ROLE name + userIdRole.erase(0, 1); + for (string::iterator p = userIdRole.begin(); p < userIdRole.end(); ++p) + { + if (*p == end_quote) + { + if (++p < userIdRole.end() && *p == end_quote) + { + // skip the escape quote here + userIdRole.erase(p--); + } + else + { + // delimited done + userIdRole.erase(--p, userIdRole.end()); + } + } + } + } + else + IntlUtil::toUpper(utf8CharSet, userIdRole); + } + break; + + default: + break; + } + } +} + JAttachment* FB_CARG JProvider::attachDatabase(IStatus* user_status, const char* filename, unsigned int dpb_length, const unsigned char* dpb) { @@ -1505,83 +1586,9 @@ Arg::Gds(isc_valid_client_dialects) << Arg::Str("1, 2 or 3")); } - if (userId.usr_sql_role_name.hasData()) - { - switch (options.dpb_sql_dialect) - { - case 0: - // V6 Client --> V6 Server, dummy client SQL dialect 0 was passed - // It means that client SQL dialect was not set by user - // and takes DB SQL dialect as client SQL dialect - if (dbb->dbb_flags & DBB_DB_SQL_dialect_3) - { - // DB created in IB V6.0 by client SQL dialect 3 - options.dpb_sql_dialect = SQL_DIALECT_V6; - } - else - { - // old DB was gbaked in IB V6.0 - options.dpb_sql_dialect = SQL_DIALECT_V5; - } - break; - case 99: - // V5 Client --> V6 Server, old client has no concept of dialect - options.dpb_sql_dialect = SQL_DIALECT_V5; - break; - default: - // V6 Client --> V6 Server, but client SQL dialect was set - // by user and was passed. - break; - } + makeRoleName(dbb, userId.usr_sql_role_name, options); + makeRoleName(dbb, userId.usr_trusted_role, options); - CharSet* utf8CharSet = IntlUtil::getUtf8CharSet(); - - switch (options.dpb_sql_dialect) - { - case SQL_DIALECT_V5: - { - strip_quotes(userId.usr_sql_role_name); - IntlUtil::toUpper(utf8CharSet, userId.usr_sql_role_name); - } - break; - - case SQL_DIALECT_V6_TRANSITION: - case SQL_DIALECT_V6: - { - string& role = userId.usr_sql_role_name; - if (role.hasData() && (role[0] == DBL_QUOTE || role[0] == SINGLE_QUOTE)) - { - const char end_quote = role[0]; - // remove the delimited quotes and escape quote - // from ROLE name - role.erase(0, 1); - for (string::iterator p = role.begin(); p < role.end(); ++p) - { - if (*p == end_quote) - { - if (++p < role.end() && *p == end_quote) - { - // skip the escape quote here - role.erase(p--); - } - else - { - // delimited done - role.erase(--p, role.end()); - } - } - } - } - else - IntlUtil::toUpper(utf8CharSet, role); - } - break; - - default: - break; - } - } - options.dpb_sql_dialect = 0; SCL_init(tdbb, false, userId); @@ -7126,10 +7133,9 @@ { user.usr_sql_role_name = options.dpb_role_name; } - else if (trusted_role.hasData()) + if (trusted_role.hasData()) { - user.usr_sql_role_name = trusted_role; - user.usr_flags |= USR_trole; + user.usr_trusted_role = trusted_role; } } Modified: firebird/trunk/src/jrd/scl.epp =================================================================== --- firebird/trunk/src/jrd/scl.epp 2014-04-30 12:20:59 UTC (rev 59507) +++ firebird/trunk/src/jrd/scl.epp 2014-04-30 15:12:12 UTC (rev 59508) @@ -804,6 +804,91 @@ } +bool SCL_role_granted(thread_db* tdbb, const UserId& usr, const TEXT* sql_role) +{ +/************************************** + * + * S C L _ r o l e _ g r a n t e d + * + ************************************** + * + * Functional description + * Check is sql_role granted to the user. + * + **************************************/ + SET_TDBB(tdbb); + Jrd::Attachment* const attachment = tdbb->getAttachment(); + + if (!strcmp(sql_role, NULL_ROLE)) + { + return true; + } + + Firebird::string loginName(usr.usr_user_name); + loginName.upper(); + const TEXT* login_name = loginName.c_str(); + + bool found = false; + + AutoCacheRequest request(tdbb, irq_verify_role_name, IRQ_REQUESTS); + + // CVC: The caller has hopefully uppercased the role or stripped quotes. Of course, + // uppercase-UPPER7 should only happen if the role wasn't enclosed in quotes. + // Shortsighted developers named the field rdb$relation_name instead of rdb$object_name. + // This request is not exactly the same than irq_get_role_mem, sorry, I can't reuse that. + // If you think that an unknown role cannot be granted, think again: someone made sure + // in DYN that SYSDBA can do almost anything, including invalid grants. + + FOR (REQUEST_HANDLE request) FIRST 1 RR IN RDB$ROLES + CROSS UU IN RDB$USER_PRIVILEGES + WITH RR.RDB$ROLE_NAME EQ sql_role + AND RR.RDB$ROLE_NAME EQ UU.RDB$RELATION_NAME + AND UU.RDB$OBJECT_TYPE EQ obj_sql_role + AND (UU.RDB$USER EQ login_name + OR UU.RDB$USER EQ "PUBLIC") + AND UU.RDB$USER_TYPE EQ obj_user + AND UU.RDB$PRIVILEGE EQ "M" + { + if (!UU.RDB$USER.NULL) + found = true; + } + END_FOR + + return found; +} + + +bool SCL_admin_role(thread_db* tdbb, const TEXT* sql_role) +{ +/************************************** + * + * S C L _ a d m i n _ r o l e + * + ************************************** + * + * Functional description + * Check is sql_role is an admin role. + * + **************************************/ + SET_TDBB(tdbb); + Jrd::Attachment* const attachment = tdbb->getAttachment(); + + bool adminRole = false; + + AutoCacheRequest request(tdbb, irq_is_admin_role, IRQ_REQUESTS); + + FOR(REQUEST_HANDLE request) R IN RDB$ROLES + WITH R.RDB$ROLE_NAME EQ sql_role + { + if (R.RDB$SYSTEM_FLAG & ROLE_FLAG_DBO) + adminRole = true; + } + END_FOR + + return adminRole; +} + + void SCL_init(thread_db* tdbb, bool create, const UserId& tempId) { /************************************** @@ -815,10 +900,8 @@ * Functional description * Check database access control list. * - * Checks the userinfo database to get the - * password and other stuff about the specified - * user. Compares the password to that passed - * in, encrypting if necessary. + * Finally fills UserId information + * (role, flags, etc.). * **************************************/ SET_TDBB(tdbb); @@ -826,17 +909,17 @@ Jrd::Attachment* const attachment = tdbb->getAttachment(); const TEXT* sql_role = tempId.usr_sql_role_name.nullStr(); - Firebird::string loginName(tempId.usr_user_name); - loginName.upper(); - const TEXT* login_name = loginName.c_str(); - Firebird::MetaName role_name; // CVC: We'll verify the role and wipe it out when it doesn't exist - if (strlen(login_name) != 0) + if (tempId.usr_user_name.hasData()) { if (!create) { + Firebird::string loginName(tempId.usr_user_name); + loginName.upper(); + const TEXT* login_name = loginName.c_str(); + AutoCacheRequest request(tdbb, irq_get_role_name, IRQ_REQUESTS); FOR(REQUEST_HANDLE request) X IN RDB$ROLES @@ -851,51 +934,17 @@ // CVC: If we aren't creating a db and sql_role was specified, // then verify it against rdb$roles and rdb$user_privileges - if (!create && sql_role && *sql_role && strcmp(sql_role, NULL_ROLE)) + if (!create && sql_role && *sql_role) { - bool found = false; + if (!SCL_role_granted(tdbb, tempId, sql_role)) + sql_role = NULL; + } - AutoCacheRequest request(tdbb, irq_verify_role_name, IRQ_REQUESTS); + if (!sql_role) + sql_role = tempId.usr_trusted_role.nullStr(); - // CVC: The caller has hopefully uppercased the role or stripped quotes. Of course, - // uppercase-UPPER7 should only happen if the role wasn't enclosed in quotes. - // Shortsighted developers named the field rdb$relation_name instead of rdb$object_name. - // This request is not exactly the same than irq_get_role_mem, sorry, I can't reuse that. - // If you think that an unknown role cannot be granted, think again: someone made sure - // in DYN that SYSDBA can do almost anything, including invalid grants. + MetaName role_name(sql_role ? sql_role : NULL_ROLE); - if (!(tempId.usr_flags & USR_trole)) - { - FOR (REQUEST_HANDLE request) FIRST 1 RR IN RDB$ROLES - CROSS UU IN RDB$USER_PRIVILEGES - WITH RR.RDB$ROLE_NAME EQ sql_role - AND RR.RDB$ROLE_NAME EQ UU.RDB$RELATION_NAME - AND UU.RDB$OBJECT_TYPE EQ obj_sql_role - AND (UU.RDB$USER EQ login_name - OR UU.RDB$USER EQ "PUBLIC") - AND UU.RDB$USER_TYPE EQ obj_user - AND UU.RDB$PRIVILEGE EQ "M" - { - if (!UU.RDB$USER.NULL) - found = true; - } - END_FOR - } - else - found = true; - - if (!found) - role_name = NULL_ROLE; - } - - if (sql_role) - { - if (role_name != NULL_ROLE) - role_name = sql_role; - } - else - role_name = NULL_ROLE; - MemoryPool& pool = *attachment->att_pool; UserId* const user = FB_NEW(pool) UserId(pool, tempId); user->usr_sql_role_name = role_name.c_str(); @@ -903,9 +952,9 @@ if (!create) { - AutoRequest handle, handle1, handle2; + AutoCacheRequest request(tdbb, irq_get_att_class, IRQ_REQUESTS); - FOR(REQUEST_HANDLE handle) X IN RDB$DATABASE + FOR(REQUEST_HANDLE request) X IN RDB$DATABASE { if (!X.RDB$SECURITY_CLASS.NULL) attachment->att_security_class = SCL_get_class(tdbb, X.RDB$SECURITY_CLASS); @@ -914,7 +963,9 @@ if (dbb->dbb_owner.isEmpty()) { - FOR(REQUEST_HANDLE handle1) + AutoRequest request; + + FOR(REQUEST_HANDLE request) FIRST 1 REL IN RDB$RELATIONS WITH REL.RDB$RELATION_NAME EQ "RDB$DATABASE" { @@ -927,13 +978,8 @@ if (dbb->dbb_owner == user->usr_user_name) user->usr_flags |= USR_owner; - FOR(REQUEST_HANDLE handle2) R IN RDB$ROLES - WITH R.RDB$ROLE_NAME EQ role_name.c_str() - { - if (R.RDB$SYSTEM_FLAG & ROLE_FLAG_DBO) - user->usr_flags |= USR_dba; - } - END_FOR + if (sql_role && SCL_admin_role(tdbb, role_name.c_str())) + user->usr_flags |= USR_dba; } else { @@ -1294,6 +1340,8 @@ case id_sql_role: if (!role_name || check_string(a, role_name)) hit = false; + else if (user.usr_sql_role_name == user.usr_trusted_role) + hit = true; else { TEXT login_name[129]; Modified: firebird/trunk/src/jrd/scl.h =================================================================== --- firebird/trunk/src/jrd/scl.h 2014-04-30 12:20:59 UTC (rev 59507) +++ firebird/trunk/src/jrd/scl.h 2014-04-30 15:12:12 UTC (rev 59508) @@ -84,14 +84,13 @@ const USHORT USR_locksmith = 1; // User has great karma const USHORT USR_dba = 2; // User has DBA privileges const USHORT USR_owner = 4; // User owns database -const USHORT USR_trole = 8; // Role was set by trusted auth - class UserId { public: Firebird::string usr_user_name; // User name Firebird::string usr_sql_role_name; // Role name + Firebird::string usr_trusted_role; // Trusted role if set Firebird::string usr_project_name; // Project name Firebird::string usr_org_name; // Organization name Firebird::string usr_auth_method; // Authentication method @@ -112,6 +111,7 @@ UserId(Firebird::MemoryPool& p, const UserId& ui) : usr_user_name(p, ui.usr_user_name), usr_sql_role_name(p, ui.usr_sql_role_name), + usr_trusted_role(p, ui.usr_trusted_role), usr_project_name(p, ui.usr_project_name), usr_org_name(p, ui.usr_org_name), usr_auth_method(p, ui.usr_auth_method), @@ -126,6 +126,7 @@ UserId(const UserId& ui) : usr_user_name(ui.usr_user_name), usr_sql_role_name(ui.usr_sql_role_name), + usr_trusted_role(ui.usr_trusted_role), usr_project_name(ui.usr_project_name), usr_org_name(ui.usr_org_name), usr_auth_method(ui.usr_auth_method), @@ -140,6 +141,7 @@ { usr_user_name = ui.usr_user_name; usr_sql_role_name = ui.usr_sql_role_name; + usr_trusted_role = ui.usr_trusted_role; usr_project_name = ui.usr_project_name; usr_org_name = ui.usr_org_name; usr_auth_method = ui.usr_auth_method; Modified: firebird/trunk/src/jrd/scl_proto.h =================================================================== --- firebird/trunk/src/jrd/scl_proto.h 2014-04-30 12:20:59 UTC (rev 59507) +++ firebird/trunk/src/jrd/scl_proto.h 2014-04-30 15:12:12 UTC (rev 59508) @@ -51,6 +51,8 @@ void SCL_init(Jrd::thread_db* tdbb, bool, const Jrd::UserId& tempId); Jrd::SecurityClass* SCL_recompute_class(Jrd::thread_db*, const TEXT*); void SCL_release_all(Jrd::SecurityClassList*&); +bool SCL_role_granted(Jrd::thread_db* tdbb, const Jrd::UserId& usr, const TEXT* sql_role); +bool SCL_admin_role(Jrd::thread_db* tdbb, const TEXT* sql_role); namespace Jrd { typedef Firebird::Array<UCHAR> Acl; Modified: firebird/trunk/src/msgs/facilities2.sql =================================================================== --- firebird/trunk/src/msgs/facilities2.sql 2014-04-30 12:20:59 UTC (rev 59507) +++ firebird/trunk/src/msgs/facilities2.sql 2014-04-30 15:12:12 UTC (rev 59508) @@ -1,7 +1,7 @@ /* MAX_NUMBER is the next number to be used, always one more than the highest message number. */ set bulk_insert INSERT INTO FACILITIES (LAST_CHANGE, FACILITY, FAC_CODE, MAX_NUMBER) VALUES (?, ?, ?, ?); -- -('2014-04-18 19:01:37', 'JRD', 0, 770) +('2014-04-30 18:55:42', 'JRD', 0, 772) ('2012-01-23 20:10:30', 'QLI', 1, 532) ('2013-11-13 15:59:10', 'GFIX', 3, 122) ('1996-11-07 13:39:40', 'GPRE', 4, 1) Modified: firebird/trunk/src/msgs/messages2.sql =================================================================== --- firebird/trunk/src/msgs/messages2.sql 2014-04-30 12:20:59 UTC (rev 59507) +++ firebird/trunk/src/msgs/messages2.sql 2014-04-30 15:12:12 UTC (rev 59508) @@ -877,6 +877,8 @@ ('baddpb_temp_buffers', 'DatabaseOptions::get', 'jrd.cpp', NULL, 0, 767, NULL, 'Attempt to temporarily set number of buffers less than @1', NULL, NULL); ('map_nodb', 'MappingList::getList', 'Mapping.cpp', NULL, 0, 768, NULL, 'Global mapping is not available when database @1 is not present', NULL, NULL); ('map_notable', 'MappingList::getList', 'Mapping.cpp', NULL, 0, 769, NULL, 'Global mapping is not available when table RDB$MAP is not present in database @1', NULL, NULL); +('miss_trusted_role', 'SetRoleNode::execute', 'StmtNodes.cpp', NULL, 0, 770, NULL, 'Your attachment has no trusted role', NULL, NULL); +('set_invalid_role', 'SetRoleNode::execute', 'StmtNodes.cpp', NULL, 0, 771, NULL, 'Role @1 is invalid or unavailable', NULL, NULL); -- QLI (NULL, NULL, NULL, NULL, 1, 0, NULL, 'expected type', NULL, NULL); (NULL, NULL, NULL, NULL, 1, 1, NULL, 'bad block type', NULL, NULL); Modified: firebird/trunk/src/msgs/system_errors2.sql =================================================================== --- firebird/trunk/src/msgs/system_errors2.sql 2014-04-30 12:20:59 UTC (rev 59507) +++ firebird/trunk/src/msgs/system_errors2.sql 2014-04-30 15:12:12 UTC (rev 59508) @@ -776,6 +776,8 @@ (-924, 'HY', '000', 0, 767, 'baddpb_temp_buffers', NULL, NULL); (-901, '0A', '000', 0, 768, 'map_nodb', NULL, NULL); (-901, '0A', '000', 0, 769, 'map_notable', NULL, NULL); +(-901, '0P', '000', 0, 770, 'miss_trusted_role', NULL, NULL); +(-901, '0P', '000', 0, 771, 'set_invalid_role', NULL, NULL); -- GFIX (-901, '00', '000', 3, 1, 'gfix_db_name', NULL, NULL) (-901, '00', '000', 3, 2, 'gfix_invalid_sw', NULL, NULL) Modified: firebird/trunk/src/yvalve/keywords.cpp =================================================================== --- firebird/trunk/src/yvalve/keywords.cpp 2014-04-30 12:20:59 UTC (rev 59507) +++ firebird/trunk/src/yvalve/keywords.cpp 2014-04-30 15:12:12 UTC (rev 59508) @@ -407,6 +407,7 @@ {TRIM, "TRIM", 2, false}, {KW_TRUE, "TRUE", 2, false}, {TRUNC, "TRUNC", 2, false}, + {TRUSTED, "TRUSTED", 2, false}, {TWO_PHASE, "TWO_PHASE", 2, true}, {KW_TYPE, "TYPE", 2, true}, {UNCOMMITTED, "UNCOMMITTED", 1, false}, This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site. |