diff options
author | Vicențiu Ciorbaru <cvicentiu@gmail.com> | 2022-01-13 22:06:13 +0200 |
---|---|---|
committer | Vicențiu Ciorbaru <vicentiu@mariadb.org> | 2022-03-12 13:29:31 +0200 |
commit | d64b6bf86ef2df310691741465b850d9859a4524 (patch) | |
tree | 51343c3d55bc2f605d92e16b6a0a6ec2c98fa69e | |
parent | 53acff81a7d3213a5fda12c2fcd89dce8b7b772a (diff) | |
download | mariadb-git-d64b6bf86ef2df310691741465b850d9859a4524.tar.gz |
WIP: Saving DB-level denies to disk and fetching them
-rw-r--r-- | sql/sql_acl.cc | 200 |
1 files changed, 196 insertions, 4 deletions
diff --git a/sql/sql_acl.cc b/sql/sql_acl.cc index ce7df1b5c93..400e748d16b 100644 --- a/sql/sql_acl.cc +++ b/sql/sql_acl.cc @@ -154,24 +154,69 @@ public: db{nullptr, 0}, table{nullptr, 0}, column{nullptr, 0}, routine{nullptr, 0} { } + Priv_spec(privilege_t access, bool revoke, LEX_CSTRING db, bool deny=false): + revoke{revoke}, deny{deny}, access{access}, + spec_type{PRIV_TYPE::DATABASE_PRIV}, db{db}, + table{nullptr, 0}, column{nullptr, 0}, routine{nullptr, 0} + { /* TODO(cvicentiu) hack */ + if (!db.str) + spec_type= PRIV_TYPE::GLOBAL_PRIV; + } }; class Deny_spec { + typedef std::pair<LEX_CSTRING, privilege_t> deny_entry; PRIV_TYPE specified_denies; privilege_t global_denies; + Hash_set<deny_entry> *db_denies; + //Dynamic_array<std::pair<LEX_CSTRING, privilege_t>> db_denies_wild; + static uchar * pair_first_key(const deny_entry *elem, + size_t *elem_size, + my_bool unused __attribute__((unused))) + { + *elem_size= elem->first.length; + return (uchar *)(elem->first.str); + } + + static void free_deny_entry(void *ptr) + { + LEX_CSTRING *entry= (LEX_CSTRING *)ptr; + my_free((void *)entry->str); + delete entry; + } + + static deny_entry *get_hash_entry(const Hash_set<deny_entry> &hash, + const LEX_CSTRING &key) + { + return hash.find(key.str, key.length); + } + // TODO(cvicentiu) proxy denies. public: - Deny_spec() : specified_denies{NO_PRIV}, global_denies{NO_ACL} {} + Deny_spec() : specified_denies{NO_PRIV}, global_denies{NO_ACL}, + db_denies{nullptr} {} ~Deny_spec() { + delete db_denies; } privilege_t get_global() const { return global_denies; } PRIV_TYPE get_specified_denies() const { return specified_denies; } + privilege_t get_db_deny(const LEX_CSTRING &db) const + { + deny_entry *res= nullptr; + if (db_denies && db.length) + res= db_denies->find(db.str, db.length); + + if (!res) + return NO_ACL; + return res->second; + } + /* { "global": int @@ -201,7 +246,36 @@ public: s->append(v, vlen); append_comma= true; } - (void) append_comma; // TODO(cvicentiu) to be used for other deny types. + if (specified_denies & DATABASE_PRIV) + { + if (append_comma) + s->append(','); + s->append(STRING_WITH_LEN("\"db\":[")); + for (size_t i= 0; i < db_denies->size(); i++) + { + const deny_entry *entry= db_denies->at(i); + char v[FLOATING_POINT_BUFFER + 1]; + size_t vlen= longlong10_to_str(entry->second, v, -10) - v; + s->append(STRING_WITH_LEN("{\"name\":\"")); + + char buf[1500]; //TODO(cvicentiu) size... + int blen= json_escape(system_charset_info, + (const uchar*)entry->first.str, + (const uchar*)entry->first.str + entry->first.length, + system_charset_info, // TODO(cvicentiu) table charset.. + (uchar*)buf, (uchar*)buf+sizeof(buf)); + if (blen < 0) + return true; + s->append(buf, blen); + s->append(STRING_WITH_LEN("\",\"access\":")); + s->append(v, vlen); + if (i != db_denies->size() - 1) + s->append(STRING_WITH_LEN("},")); + else + s->append(STRING_WITH_LEN("}")); + } + s->append(']'); + } s->append('}'); return false; } @@ -220,9 +294,52 @@ public: break; } case DATABASE_PRIV: - // TODO(cvicentiu) - DBUG_ASSERT(0); + { + deny_entry *entry= nullptr; + if (!db_denies) + { + db_denies= new Hash_set<deny_entry>( + PSI_INSTRUMENT_MEM, &my_charset_bin, 10, 0, 0, + (my_hash_get_key)pair_first_key, + free_deny_entry, HASH_UNIQUE); + if (!db_denies) + return true; + } + else + entry= get_hash_entry(*db_denies, priv_spec.db); + bool entry_exists= entry != nullptr; + if (!entry) /* No previous entry */ + { + + entry= new deny_entry(); + if (!entry) + return true; + entry->first.str= my_strdup(PSI_INSTRUMENT_MEM, priv_spec.db.str, MYF(0)); + if (!entry->first.str) + { + my_free(const_cast<char*>(entry->first.str)); + delete entry; + return true; + } + entry->first.length= priv_spec.db.length; + } + + if (priv_spec.revoke) + entry->second&= ~priv_spec.access; + else + entry->second|= priv_spec.access; + + if (!entry_exists) + { + if (db_denies->insert(entry)) + { + delete entry; + return true; + } + } + break; + } case TABLE_PRIV: // TODO(cvicentiu) DBUG_ASSERT(0); @@ -272,6 +389,80 @@ public: if (global_denies) specified_denies= GLOBAL_PRIV; } + + value_type= json_get_object_key(start, end, "db", &v, &int_vl); + if (value_type != JSV_ARRAY && value_type != JSV_NOTHING) + return true; + + if (value_type != JSV_NOTHING) + { + const char *array_start= v; + const char *array_end= v + int_vl; + int idx= 0; + + DBUG_ASSERT(!db_denies); + db_denies= new Hash_set<deny_entry>( + PSI_INSTRUMENT_MEM, &my_charset_bin, 10, 0, 0, + (my_hash_get_key)pair_first_key, + free_deny_entry, HASH_UNIQUE); + + while (true) + { + const char *db_deny_obj_start; + int db_deny_obj_len; + + const char *name_start; + int name_len; + const char *access_start; + int access_len; + const char *access_end; + privilege_t db_deny; + + value_type= json_get_array_item(array_start, array_end, idx, + &db_deny_obj_start, + &db_deny_obj_len); + if (value_type == JSV_NOTHING) + break; + if (value_type != JSV_OBJECT) + return true; + + value_type= json_get_object_key(db_deny_obj_start, end, "name", + &name_start, &name_len); + if (value_type != JSV_STRING) + return true; + + value_type= json_get_object_key(db_deny_obj_start, end, "access", + &access_start, &access_len); + if (value_type != JSV_NUMBER) + return true; + + access_end= access_start + access_len; + db_deny= static_cast<privilege_t>( + my_strtoll10(access_start, (char **)&access_end, &err)); + if (err) + return true; + + deny_entry *entry= new deny_entry(); + + if (!entry) + return true; + + entry->first.str= my_strndup(PSI_INSTRUMENT_MEM, name_start, + static_cast<size_t>(name_len), MYF(0)); + if (!entry->first.str) + { + delete entry; + return true; + } + entry->first.length= static_cast<size_t>(name_len); + + entry->second= db_deny; + db_denies->insert(entry); + if (global_denies) + specified_denies|= DATABASE_PRIV; + idx++; + } + } // TODO(cvicentiu) continue loading db denies and other json denies. return false; } @@ -4608,6 +4799,7 @@ privilege_t acl_get_effective_deny_mask(const Security_context *ctx, } result= acl_user->denies->get_global(); + result|= acl_user->denies->get_db_deny(db); //TODO(cvicentiu) roles mysql_mutex_unlock(&acl_cache->lock); |