OmniSciDB  0b528656ed
SysCatalog.cpp
Go to the documentation of this file.
1 /*
2  * Copyright 2019 MapD Technologies, Inc.
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  * http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 
25 #include "SysCatalog.h"
26 #include <algorithm>
27 #include <cassert>
28 #include <exception>
29 #include <list>
30 #include <memory>
31 #include <random>
32 #include <sstream>
33 #include <string_view>
34 #include "Catalog.h"
35 
36 #include "Catalog/AuthMetadata.h"
37 #include "LockMgr/LockMgr.h"
39 
40 #include <boost/algorithm/string/predicate.hpp>
41 #include <boost/filesystem.hpp>
42 #include <boost/range/adaptor/map.hpp>
43 #include <boost/version.hpp>
44 
45 #include "../Parser/ParserNode.h"
46 #include "../Shared/File.h"
47 #include "../Shared/StringTransform.h"
48 #include "../Shared/measure.h"
49 #include "MapDRelease.h"
50 #include "RWLocks.h"
51 #include "bcrypt.h"
52 
53 using std::list;
54 using std::map;
55 using std::pair;
56 using std::runtime_error;
57 using std::string;
58 using std::vector;
59 
60 using namespace std::string_literals;
61 
62 extern bool g_enable_fsi;
63 
64 namespace {
65 
66 std::string hash_with_bcrypt(const std::string& pwd) {
67  char salt[BCRYPT_HASHSIZE], hash[BCRYPT_HASHSIZE];
68  CHECK(bcrypt_gensalt(-1, salt) == 0);
69  CHECK(bcrypt_hashpw(pwd.c_str(), salt, hash) == 0);
70  return std::string(hash, BCRYPT_HASHSIZE);
71 }
72 
73 } // namespace
74 
75 namespace Catalog_Namespace {
76 
77 thread_local bool SysCatalog::thread_holds_read_lock = false;
78 
79 using sys_read_lock = read_lock<SysCatalog>;
82 
83 auto CommonFileOperations::assembleCatalogName(std::string const& name) {
84  return base_path_ + "/mapd_catalogs/" + name;
85 };
86 
87 void CommonFileOperations::removeCatalogByFullPath(std::string const& full_path) {
88  boost::filesystem::remove(full_path);
89 }
90 
91 void CommonFileOperations::removeCatalogByName(std::string const& name) {
92  boost::filesystem::remove(assembleCatalogName(name));
93 };
94 
95 auto CommonFileOperations::duplicateAndRenameCatalog(std::string const& current_name,
96  std::string const& new_name) {
97  auto full_current_path = assembleCatalogName(current_name);
98  auto full_new_path = assembleCatalogName(new_name);
99 
100  try {
101  boost::filesystem::copy_file(full_current_path, full_new_path);
102  } catch (std::exception& e) {
103  std::string err_message{"Could not copy file " + full_current_path + " to " +
104  full_new_path + " exception was " + e.what()};
105  LOG(ERROR) << err_message;
106  throw std::runtime_error(err_message);
107  }
108 
109  return std::make_pair(full_current_path, full_new_path);
110 };
111 
112 void SysCatalog::init(const std::string& basePath,
113  std::shared_ptr<Data_Namespace::DataMgr> dataMgr,
114  const AuthMetadata& authMetadata,
115  std::shared_ptr<Calcite> calcite,
116  bool is_new_db,
117  bool aggregator,
118  const std::vector<LeafHostInfo>& string_dict_hosts) {
119  {
122 
123  basePath_ = basePath;
124  dataMgr_ = dataMgr;
125  authMetadata_ = &authMetadata;
126  ldap_server_.reset(new LdapServer(*authMetadata_));
127  rest_server_.reset(new RestServer(*authMetadata_));
128  pki_server_.reset(new PkiServer(*authMetadata_));
129  calciteMgr_ = calcite;
130  string_dict_hosts_ = string_dict_hosts;
131  aggregator_ = aggregator;
132  bool db_exists =
133  boost::filesystem::exists(basePath_ + "/mapd_catalogs/" + OMNISCI_SYSTEM_CATALOG);
134  sqliteConnector_.reset(
135  new SqliteConnector(OMNISCI_SYSTEM_CATALOG, basePath_ + "/mapd_catalogs/"));
136  if (is_new_db) {
137  initDB();
138  } else {
139  if (!db_exists) {
140  importDataFromOldMapdDB();
141  }
142  checkAndExecuteMigrations();
143  }
144  buildRoleMap();
145  buildUserRoleMap();
146  buildObjectDescriptorMap();
147  }
148 }
149 
150 SysCatalog::~SysCatalog() {
152  for (auto grantee = granteeMap_.begin(); grantee != granteeMap_.end(); ++grantee) {
153  delete grantee->second;
154  }
155  granteeMap_.clear();
156  for (ObjectRoleDescriptorMap::iterator objectIt = objectDescriptorMap_.begin();
157  objectIt != objectDescriptorMap_.end();) {
158  ObjectRoleDescriptorMap::iterator eraseIt = objectIt++;
159  delete eraseIt->second;
160  }
161  objectDescriptorMap_.clear();
162 }
163 
164 void SysCatalog::initDB() {
166  sqliteConnector_->query("BEGIN TRANSACTION");
167  try {
168  sqliteConnector_->query(
169  "CREATE TABLE mapd_users (userid integer primary key, name text unique, "
170  "passwd_hash text, issuper boolean, default_db integer references "
171  "mapd_databases, can_login boolean)");
172  sqliteConnector_->query_with_text_params(
173  "INSERT INTO mapd_users VALUES (?, ?, ?, 1, NULL, 1)",
174  std::vector<std::string>{OMNISCI_ROOT_USER_ID_STR,
177  sqliteConnector_->query(
178  "CREATE TABLE mapd_databases (dbid integer primary key, name text unique, owner "
179  "integer references mapd_users)");
180  sqliteConnector_->query(
181  "CREATE TABLE mapd_roles(roleName text, userName text, UNIQUE(roleName, "
182  "userName))");
183  sqliteConnector_->query(
184  "CREATE TABLE mapd_object_permissions ("
185  "roleName text, "
186  "roleType bool, "
187  "dbId integer references mapd_databases, "
188  "objectName text, "
189  "objectId integer, "
190  "objectPermissionsType integer, "
191  "objectPermissions integer, "
192  "objectOwnerId integer, UNIQUE(roleName, objectPermissionsType, dbId, "
193  "objectId))");
194  } catch (const std::exception&) {
195  sqliteConnector_->query("ROLLBACK TRANSACTION");
196  throw;
197  }
198  sqliteConnector_->query("END TRANSACTION");
199  createDatabase(OMNISCI_DEFAULT_DB, OMNISCI_ROOT_USER_ID);
200 }
201 
202 void SysCatalog::checkAndExecuteMigrations() {
203  migratePrivileged_old();
204  createUserRoles();
205  migratePrivileges();
206  migrateDBAccessPrivileges();
207  updateUserSchema(); // must come before updatePasswordsToHashes()
208  updatePasswordsToHashes();
209  updateBlankPasswordsToRandom(); // must come after updatePasswordsToHashes()
210  updateSupportUserDeactivation();
211 }
212 
213 void SysCatalog::updateUserSchema() {
215 
216  // check to see if the new column already exists
217  sqliteConnector_->query("PRAGMA TABLE_INFO(mapd_users)");
218  for (size_t i = 0; i < sqliteConnector_->getNumRows(); i++) {
219  const auto& col_name = sqliteConnector_->getData<std::string>(i, 1);
220  if (col_name == "default_db") {
221  return; // new column already exists
222  }
223  }
224 
225  // create the new column
226  sqliteConnector_->query("BEGIN TRANSACTION");
227  try {
228  sqliteConnector_->query(
229  "ALTER TABLE mapd_users ADD COLUMN default_db INTEGER REFERENCES mapd_databases");
230  } catch (const std::exception& e) {
231  sqliteConnector_->query("ROLLBACK TRANSACTION");
232  throw;
233  }
234  sqliteConnector_->query("END TRANSACTION");
235 }
236 
237 void SysCatalog::importDataFromOldMapdDB() {
239  std::string mapd_db_path = basePath_ + "/mapd_catalogs/mapd";
240  sqliteConnector_->query("ATTACH DATABASE `" + mapd_db_path + "` as old_cat");
241  sqliteConnector_->query("BEGIN TRANSACTION");
242  LOG(INFO) << "Moving global metadata into a separate catalog";
243  try {
244  auto moveTableIfExists = [conn = sqliteConnector_.get()](const std::string& tableName,
245  bool deleteOld = true) {
246  conn->query("SELECT sql FROM old_cat.sqlite_master WHERE type='table' AND name='" +
247  tableName + "'");
248  if (conn->getNumRows() != 0) {
249  conn->query(conn->getData<string>(0, 0));
250  conn->query("INSERT INTO " + tableName + " SELECT * FROM old_cat." + tableName);
251  if (deleteOld) {
252  conn->query("DROP TABLE old_cat." + tableName);
253  }
254  }
255  };
256  moveTableIfExists("mapd_users");
257  moveTableIfExists("mapd_databases");
258  moveTableIfExists("mapd_roles");
259  moveTableIfExists("mapd_object_permissions");
260  moveTableIfExists("mapd_privileges");
261  moveTableIfExists("mapd_version_history", false);
262  } catch (const std::exception& e) {
263  LOG(ERROR) << "Failed to move global metadata into a separate catalog: " << e.what();
264  sqliteConnector_->query("ROLLBACK TRANSACTION");
265  try {
266  sqliteConnector_->query("DETACH DATABASE old_cat");
267  } catch (const std::exception&) {
268  // nothing to do here
269  }
270  throw;
271  }
272  sqliteConnector_->query("END TRANSACTION");
273  const std::string sys_catalog_path =
274  basePath_ + "/mapd_catalogs/" + OMNISCI_SYSTEM_CATALOG;
275  LOG(INFO) << "Global metadata has been successfully moved into a separate catalog: "
276  << sys_catalog_path
277  << ". Using this database with an older version of omnisci_server "
278  "is now impossible.";
279  try {
280  sqliteConnector_->query("DETACH DATABASE old_cat");
281  } catch (const std::exception&) {
282  // nothing to do here
283  }
284 }
285 
286 void SysCatalog::createUserRoles() {
288  sqliteConnector_->query("BEGIN TRANSACTION");
289  try {
290  sqliteConnector_->query(
291  "SELECT name FROM sqlite_master WHERE type='table' AND name='mapd_roles'");
292  if (sqliteConnector_->getNumRows() != 0) {
293  // already done
294  sqliteConnector_->query("END TRANSACTION");
295  return;
296  }
297  sqliteConnector_->query(
298  "CREATE TABLE mapd_roles(roleName text, userName text, UNIQUE(roleName, "
299  "userName))");
300  // need to account for old conversions where we are building and moving
301  // from pre version 4.0 and 'mapd' was default superuser
302  sqliteConnector_->query("SELECT name FROM mapd_users WHERE name NOT IN ( \'" +
303  OMNISCI_ROOT_USER + "\', 'mapd')");
304  size_t numRows = sqliteConnector_->getNumRows();
305  vector<string> user_names;
306  for (size_t i = 0; i < numRows; ++i) {
307  user_names.push_back(sqliteConnector_->getData<string>(i, 0));
308  }
309  for (const auto& user_name : user_names) {
310  // for each user, create a fake role with the same name
311  sqliteConnector_->query_with_text_params(
312  "INSERT INTO mapd_roles(roleName, userName) VALUES (?, ?)",
313  vector<string>{user_name, user_name});
314  }
315  } catch (const std::exception&) {
316  sqliteConnector_->query("ROLLBACK TRANSACTION");
317  throw;
318  }
319  sqliteConnector_->query("END TRANSACTION");
320 }
321 
322 void deleteObjectPrivileges(std::unique_ptr<SqliteConnector>& sqliteConnector,
323  std::string roleName,
324  bool userRole,
325  DBObject& object) {
326  DBObjectKey key = object.getObjectKey();
327 
328  sqliteConnector->query_with_text_params(
329  "DELETE FROM mapd_object_permissions WHERE roleName = ?1 and roleType = ?2 and "
330  "objectPermissionsType = ?3 and "
331  "dbId = "
332  "?4 "
333  "and objectId = ?5",
334  std::vector<std::string>{roleName,
335  std::to_string(userRole),
337  std::to_string(key.dbId),
338  std::to_string(key.objectId)});
339 }
340 
341 void insertOrUpdateObjectPrivileges(std::unique_ptr<SqliteConnector>& sqliteConnector,
342  std::string roleName,
343  bool userRole,
344  DBObject& object) {
345  DBObjectKey key = object.getObjectKey();
346 
347  sqliteConnector->query_with_text_params(
348  "INSERT OR REPLACE INTO mapd_object_permissions("
349  "roleName, "
350  "roleType, "
351  "objectPermissionsType, "
352  "dbId, "
353  "objectId, "
354  "objectPermissions, "
355  "objectOwnerId,"
356  "objectName) "
357  "VALUES (?1, ?2, ?3, "
358  "?4, ?5, ?6, ?7, ?8)",
359  std::vector<std::string>{
360  roleName, // roleName
361  userRole ? "1" : "0", // roleType
362  std::to_string(key.permissionType), // permissionType
363  std::to_string(key.dbId), // dbId
364  std::to_string(key.objectId), // objectId
365  std::to_string(object.getPrivileges().privileges), // objectPrivileges
366  std::to_string(object.getOwner()), // objectOwnerId
367  object.getName() // name
368  });
369 }
370 
371 void SysCatalog::migratePrivileges() {
373  sqliteConnector_->query("BEGIN TRANSACTION");
374  try {
375  sqliteConnector_->query(
376  "SELECT name FROM sqlite_master WHERE type='table' AND "
377  "name='mapd_object_permissions'");
378  if (sqliteConnector_->getNumRows() != 0) {
379  // already done
380  sqliteConnector_->query("END TRANSACTION");
381  return;
382  }
383 
384  sqliteConnector_->query(
385  "CREATE TABLE IF NOT EXISTS mapd_object_permissions ("
386  "roleName text, "
387  "roleType bool, "
388  "dbId integer references mapd_databases, "
389  "objectName text, "
390  "objectId integer, "
391  "objectPermissionsType integer, "
392  "objectPermissions integer, "
393  "objectOwnerId integer, UNIQUE(roleName, objectPermissionsType, dbId, "
394  "objectId))");
395 
396  // get the list of databases and their grantees
397  sqliteConnector_->query(
398  "SELECT userid, dbid FROM mapd_privileges WHERE select_priv = 1 and insert_priv "
399  "= 1");
400  size_t numRows = sqliteConnector_->getNumRows();
401  vector<pair<int, int>> db_grantees(numRows);
402  for (size_t i = 0; i < numRows; ++i) {
403  db_grantees[i].first = sqliteConnector_->getData<int>(i, 0);
404  db_grantees[i].second = sqliteConnector_->getData<int>(i, 1);
405  }
406  // map user names to user ids
407  sqliteConnector_->query("select userid, name from mapd_users");
408  numRows = sqliteConnector_->getNumRows();
409  std::unordered_map<int, string> users_by_id;
410  std::unordered_map<int, bool> user_has_privs;
411  for (size_t i = 0; i < numRows; ++i) {
412  users_by_id[sqliteConnector_->getData<int>(i, 0)] =
413  sqliteConnector_->getData<string>(i, 1);
414  user_has_privs[sqliteConnector_->getData<int>(i, 0)] = false;
415  }
416  // map db names to db ids
417  sqliteConnector_->query("select dbid, name from mapd_databases");
418  numRows = sqliteConnector_->getNumRows();
419  std::unordered_map<int, string> dbs_by_id;
420  for (size_t i = 0; i < numRows; ++i) {
421  dbs_by_id[sqliteConnector_->getData<int>(i, 0)] =
422  sqliteConnector_->getData<string>(i, 1);
423  }
424  // migrate old privileges to new privileges: if user had insert access to database, he
425  // was a grantee
426  for (const auto& grantee : db_grantees) {
427  user_has_privs[grantee.first] = true;
428  auto dbName = dbs_by_id[grantee.second];
429  {
430  // table level permissions
431  DBObjectKey key;
433  key.dbId = grantee.second;
435  object.setName(dbName);
437  sqliteConnector_, users_by_id[grantee.first], true, object);
438  }
439 
440  {
441  // dashboard level permissions
442  DBObjectKey key;
444  key.dbId = grantee.second;
445  DBObject object(
447  object.setName(dbName);
449  sqliteConnector_, users_by_id[grantee.first], true, object);
450  }
451 
452  {
453  // view level permissions
454  DBObjectKey key;
456  key.dbId = grantee.second;
458  object.setName(dbName);
460  sqliteConnector_, users_by_id[grantee.first], true, object);
461  }
462  }
463  for (auto user : user_has_privs) {
464  auto dbName = dbs_by_id[0];
465  if (user.second == false && user.first != OMNISCI_ROOT_USER_ID) {
466  {
467  DBObjectKey key;
469  key.dbId = 0;
471  object.setName(dbName);
473  sqliteConnector_, users_by_id[user.first], true, object);
474  }
475  }
476  }
477  } catch (const std::exception&) {
478  sqliteConnector_->query("ROLLBACK TRANSACTION");
479  throw;
480  }
481  sqliteConnector_->query("END TRANSACTION");
482 }
483 
484 void SysCatalog::updatePasswordsToHashes() {
486  sqliteConnector_->query("BEGIN TRANSACTION");
487  try {
488  sqliteConnector_->query(
489  "SELECT name FROM sqlite_master WHERE type='table' AND name='mapd_users'");
490  if (sqliteConnector_->getNumRows() == 0) {
491  // Nothing to update
492  sqliteConnector_->query("END TRANSACTION");
493  return;
494  }
495  sqliteConnector_->query("PRAGMA TABLE_INFO(mapd_users)");
496  for (size_t i = 0; i < sqliteConnector_->getNumRows(); i++) {
497  const auto& col_name = sqliteConnector_->getData<std::string>(i, 1);
498  if (col_name == "passwd_hash") {
499  sqliteConnector_->query("END TRANSACTION");
500  return;
501  }
502  }
503  // Alas, SQLite can't drop columns so we have to recreate the table
504  // (or, optionally, add the new column and reset the old one to a bunch of nulls)
505  sqliteConnector_->query("SELECT userid, passwd FROM mapd_users");
506  auto numRows = sqliteConnector_->getNumRows();
507  vector<std::string> users, passwords;
508  for (size_t i = 0; i < numRows; i++) {
509  users.push_back(sqliteConnector_->getData<std::string>(i, 0));
510  passwords.push_back(sqliteConnector_->getData<std::string>(i, 1));
511  }
512  sqliteConnector_->query(
513  "CREATE TABLE mapd_users_tmp (userid integer primary key, name text unique, "
514  "passwd_hash text, issuper boolean, default_db integer references "
515  "mapd_databases)");
516  sqliteConnector_->query(
517  "INSERT INTO mapd_users_tmp(userid, name, passwd_hash, issuper, default_db) "
518  "SELECT userid, name, null, issuper, default_db FROM mapd_users");
519  for (size_t i = 0; i < users.size(); ++i) {
520  sqliteConnector_->query_with_text_params(
521  "UPDATE mapd_users_tmp SET passwd_hash = ? WHERE userid = ?",
522  std::vector<std::string>{hash_with_bcrypt(passwords[i]), users[i]});
523  }
524  sqliteConnector_->query("DROP TABLE mapd_users");
525  sqliteConnector_->query("ALTER TABLE mapd_users_tmp RENAME TO mapd_users");
526  } catch (const std::exception& e) {
527  LOG(ERROR) << "Failed to hash passwords: " << e.what();
528  sqliteConnector_->query("ROLLBACK TRANSACTION");
529  throw;
530  }
531  sqliteConnector_->query("END TRANSACTION");
532  sqliteConnector_->query("VACUUM"); // physically delete plain text passwords
533  LOG(INFO) << "Passwords were successfully hashed";
534 }
535 
536 void SysCatalog::updateBlankPasswordsToRandom() {
537  const std::string UPDATE_BLANK_PASSWORDS_TO_RANDOM = "update_blank_passwords_to_random";
538  sqliteConnector_->query_with_text_params(
539  "SELECT migration_history FROM mapd_version_history WHERE migration_history = ?",
540  std::vector<std::string>{UPDATE_BLANK_PASSWORDS_TO_RANDOM});
541  if (sqliteConnector_->getNumRows()) {
542  return;
543  }
544 
546  sqliteConnector_->query("BEGIN TRANSACTION");
547  try {
548  sqliteConnector_->query(
549  "SELECT userid, passwd_hash, name FROM mapd_users WHERE name <> 'mapd'");
550  auto numRows = sqliteConnector_->getNumRows();
551  vector<std::string> users, passwords, names;
552  for (size_t i = 0; i < numRows; i++) {
553  users.push_back(sqliteConnector_->getData<std::string>(i, 0));
554  passwords.push_back(sqliteConnector_->getData<std::string>(i, 1));
555  names.push_back(sqliteConnector_->getData<std::string>(i, 2));
556  }
557  for (size_t i = 0; i < users.size(); ++i) {
558  int pwd_check_result = bcrypt_checkpw("", passwords[i].c_str());
559  // if the check fails there is a good chance that data on disc is broken
560  CHECK(pwd_check_result >= 0);
561  if (pwd_check_result != 0) {
562  continue;
563  }
564  LOG(WARNING) << "resetting blank password for user " << names[i] << " (" << users[i]
565  << ") to a random password";
566  sqliteConnector_->query_with_text_params(
567  "UPDATE mapd_users SET passwd_hash = ? WHERE userid = ?",
568  std::vector<std::string>{hash_with_bcrypt(generate_random_string(72)),
569  users[i]});
570  }
571  sqliteConnector_->query_with_text_params(
572  "INSERT INTO mapd_version_history(version, migration_history) values(?,?)",
573  std::vector<std::string>{std::to_string(MAPD_VERSION),
574  UPDATE_BLANK_PASSWORDS_TO_RANDOM});
575  } catch (const std::exception& e) {
576  LOG(ERROR) << "Failed to fix blank passwords: " << e.what();
577  sqliteConnector_->query("ROLLBACK TRANSACTION");
578  throw;
579  }
580  sqliteConnector_->query("END TRANSACTION");
581 }
582 
583 void SysCatalog::updateSupportUserDeactivation() {
584  const std::string UPDATE_SUPPORT_USER_DEACTIVATION = "update_support_user_deactivation";
586  // check to see if the new column already exists
587  sqliteConnector_->query("PRAGMA TABLE_INFO(mapd_users)");
588  for (size_t i = 0; i < sqliteConnector_->getNumRows(); i++) {
589  const auto& col_name = sqliteConnector_->getData<std::string>(i, 1);
590  if (col_name == "can_login") {
591  return; // new column already exists
592  }
593  }
594  sqliteConnector_->query("BEGIN TRANSACTION");
595  try {
596  sqliteConnector_->query("ALTER TABLE mapd_users ADD COLUMN can_login BOOLEAN");
597  sqliteConnector_->query("UPDATE mapd_users SET can_login = true");
598  sqliteConnector_->query_with_text_params(
599  "INSERT INTO mapd_version_history(version, migration_history) values(?,?)",
600  std::vector<std::string>{std::to_string(MAPD_VERSION),
601  UPDATE_SUPPORT_USER_DEACTIVATION});
602  } catch (const std::exception& e) {
603  LOG(ERROR) << "Failed to add support for user deactivation: " << e.what();
604  sqliteConnector_->query("ROLLBACK TRANSACTION");
605  throw;
606  }
607  sqliteConnector_->query("END TRANSACTION");
608 }
609 
610 void SysCatalog::migrateDBAccessPrivileges() {
612  sqliteConnector_->query("BEGIN TRANSACTION");
613  try {
614  sqliteConnector_->query(
615  "select name from sqlite_master WHERE type='table' AND "
616  "name='mapd_version_history'");
617  if (sqliteConnector_->getNumRows() == 0) {
618  sqliteConnector_->query(
619  "CREATE TABLE mapd_version_history(version integer, migration_history text "
620  "unique)");
621  } else {
622  sqliteConnector_->query(
623  "select * from mapd_version_history where migration_history = "
624  "'db_access_privileges'");
625  if (sqliteConnector_->getNumRows() != 0) {
626  // both privileges migrated
627  // no need for further execution
628  sqliteConnector_->query("END TRANSACTION");
629  return;
630  }
631  }
632  // Insert check for migration
633  sqliteConnector_->query_with_text_params(
634  "INSERT INTO mapd_version_history(version, migration_history) values(?,?)",
635  std::vector<std::string>{std::to_string(MAPD_VERSION), "db_access_privileges"});
636 
637  sqliteConnector_->query("select dbid, name from mapd_databases");
638  std::unordered_map<int, string> databases;
639  for (size_t i = 0; i < sqliteConnector_->getNumRows(); ++i) {
640  databases[sqliteConnector_->getData<int>(i, 0)] =
641  sqliteConnector_->getData<string>(i, 1);
642  }
643 
644  sqliteConnector_->query("select userid, name from mapd_users");
645  std::unordered_map<int, string> users;
646  for (size_t i = 0; i < sqliteConnector_->getNumRows(); ++i) {
647  users[sqliteConnector_->getData<int>(i, 0)] =
648  sqliteConnector_->getData<string>(i, 1);
649  }
650 
651  // All existing users by default will be granted DB Access permissions
652  // and view sql editor privileges
653  DBMetadata dbmeta;
654  for (auto db_ : databases) {
655  CHECK(SysCatalog::instance().getMetadataForDB(db_.second, dbmeta));
656  for (auto user : users) {
657  if (user.first != OMNISCI_ROOT_USER_ID) {
658  {
659  DBObjectKey key;
661  key.dbId = dbmeta.dbId;
662 
663  // access permission;
664  DBObject object_access(key, AccessPrivileges::ACCESS, dbmeta.dbOwner);
666  object_access.setName(dbmeta.dbName);
667  // sql_editor permission
668  DBObject object_editor(
671  object_editor.setName(dbmeta.dbName);
672  object_editor.updatePrivileges(object_access);
674  sqliteConnector_, user.second, true, object_editor);
675  }
676  }
677  }
678  }
679  } catch (const std::exception& e) {
680  LOG(ERROR) << "Failed to migrate db access privileges: " << e.what();
681  sqliteConnector_->query("ROLLBACK TRANSACTION");
682  throw;
683  }
684  sqliteConnector_->query("END TRANSACTION");
685  LOG(INFO) << "Successfully migrated db access privileges";
686 }
687 
688 void SysCatalog::migratePrivileged_old() {
690 
691  sqliteConnector_->query("BEGIN TRANSACTION");
692  try {
693  sqliteConnector_->query(
694  "CREATE TABLE IF NOT EXISTS mapd_privileges (userid integer references "
695  "mapd_users, dbid integer references "
696  "mapd_databases, select_priv boolean, insert_priv boolean, UNIQUE(userid, "
697  "dbid))");
698  } catch (const std::exception& e) {
699  sqliteConnector_->query("ROLLBACK TRANSACTION");
700  throw;
701  }
702  sqliteConnector_->query("END TRANSACTION");
703 }
704 
705 std::shared_ptr<Catalog> SysCatalog::login(std::string& dbname,
706  std::string& username,
707  const std::string& password,
708  UserMetadata& user_meta,
709  bool check_password) {
710  // NOTE(sy): The dbname isn't const because getMetadataWithDefaultDB()
711  // can reset it. The username isn't const because SamlServer's
712  // login()/authenticate_user() can reset it.
713 
715  if (check_password) {
716  loginImpl(username, password, user_meta);
717  } else { // not checking for password so user must exist
718  if (!getMetadataForUser(username, user_meta)) {
719  throw std::runtime_error("Invalid credentials.");
720  }
721  }
722  // we should have a user and user_meta by now
723  if (!user_meta.can_login) {
724  throw std::runtime_error("Unauthorized Access: User " + username + " is deactivated");
725  }
727  getMetadataWithDefaultDB(dbname, username, db_meta, user_meta);
728  return Catalog::get(
729  basePath_, db_meta, dataMgr_, string_dict_hosts_, calciteMgr_, false);
730 }
731 
732 // loginImpl() with no EE code and no SAML code
733 void SysCatalog::loginImpl(std::string& username,
734  const std::string& password,
735  UserMetadata& user_meta) {
736  if (!checkPasswordForUser(password, username, user_meta)) {
737  throw std::runtime_error("Authentication failure");
738  }
739 }
740 
741 std::shared_ptr<Catalog> SysCatalog::switchDatabase(std::string& dbname,
742  const std::string& username) {
743  DBMetadata db_meta;
744  UserMetadata user_meta;
745 
746  getMetadataWithDefaultDB(dbname, username, db_meta, user_meta);
747 
748  // NOTE(max): register database in Catalog that early to allow ldap
749  // and saml create default user and role privileges on databases
750  auto cat =
751  Catalog::get(basePath_, db_meta, dataMgr_, string_dict_hosts_, calciteMgr_, false);
752 
753  DBObject dbObject(dbname, DatabaseDBObjectType);
754  dbObject.loadKey();
756  if (!checkPrivileges(user_meta, std::vector<DBObject>{dbObject})) {
757  throw std::runtime_error("Unauthorized Access: user " + username +
758  " is not allowed to access database " + dbname + ".");
759  }
760 
761  return cat;
762 }
763 
764 void SysCatalog::check_for_session_encryption(const std::string& pki_cert,
765  std::string& session) {
766  if (!pki_server_->inUse()) {
767  return;
768  }
769  pki_server_->encrypt_session(pki_cert, session);
770 }
771 
772 void SysCatalog::createUser(const string& name,
773  const string& passwd,
774  bool issuper,
775  const std::string& dbname,
776  bool can_login) {
779 
780  UserMetadata user;
781  if (getMetadataForUser(name, user)) {
782  throw runtime_error("User " + name + " already exists.");
783  }
784  if (getGrantee(name)) {
785  throw runtime_error(
786  "User name " + name +
787  " is same as one of existing grantees. User and role names should be unique.");
788  }
789  sqliteConnector_->query("BEGIN TRANSACTION");
790  try {
791  std::vector<std::string> vals;
792  if (!dbname.empty()) {
793  DBMetadata db;
794  if (!SysCatalog::instance().getMetadataForDB(dbname, db)) {
795  throw runtime_error("DEFAULT_DB " + dbname + " not found.");
796  }
797  vals = {name,
798  hash_with_bcrypt(passwd),
799  std::to_string(issuper),
800  std::to_string(db.dbId),
801  std::to_string(can_login)};
802  sqliteConnector_->query_with_text_params(
803  "INSERT INTO mapd_users (name, passwd_hash, issuper, default_db, can_login) "
804  "VALUES (?, ?, ?, ?, ?)",
805  vals);
806  } else {
807  vals = {name,
808  hash_with_bcrypt(passwd),
809  std::to_string(issuper),
810  std::to_string(can_login)};
811  sqliteConnector_->query_with_text_params(
812  "INSERT INTO mapd_users (name, passwd_hash, issuper, can_login) "
813  "VALUES (?, ?, ?, ?)",
814  vals);
815  }
816  createRole_unsafe(name, true);
817  } catch (const std::exception& e) {
818  sqliteConnector_->query("ROLLBACK TRANSACTION");
819  throw;
820  }
821  sqliteConnector_->query("END TRANSACTION");
822 }
823 
824 void SysCatalog::dropUser(const string& name) {
827 
828  sqliteConnector_->query("BEGIN TRANSACTION");
829  try {
830  UserMetadata user;
831  if (!getMetadataForUser(name, user)) {
832  throw runtime_error("User " + name + " does not exist.");
833  }
834  dropRole_unsafe(name);
835  deleteObjectDescriptorMap(name);
836  const std::string& roleName(name);
837  sqliteConnector_->query_with_text_param("DELETE FROM mapd_roles WHERE userName = ?",
838  roleName);
839  sqliteConnector_->query("DELETE FROM mapd_users WHERE userid = " +
840  std::to_string(user.userId));
841  sqliteConnector_->query("DELETE FROM mapd_privileges WHERE userid = " +
842  std::to_string(user.userId));
843  } catch (const std::exception& e) {
844  sqliteConnector_->query("ROLLBACK TRANSACTION");
845  throw;
846  }
847  sqliteConnector_->query("END TRANSACTION");
848 }
849 
850 namespace { // anonymous namespace
851 
852 auto append_with_commas = [](string& s, const string& t) {
853  if (!s.empty()) {
854  s += ", ";
855  }
856  s += t;
857 };
858 
859 } // anonymous namespace
860 
861 void SysCatalog::alterUser(const int32_t userid,
862  const string* passwd,
863  bool* issuper,
864  const string* dbname,
865  bool* can_login) {
867  sqliteConnector_->query("BEGIN TRANSACTION");
868  try {
869  string sql;
870  std::vector<std::string> values;
871  if (passwd != nullptr) {
872  append_with_commas(sql, "passwd_hash = ?");
873  values.push_back(hash_with_bcrypt(*passwd));
874  }
875  if (issuper != nullptr) {
876  append_with_commas(sql, "issuper = ?");
877  values.push_back(std::to_string(*issuper));
878  }
879  if (dbname != nullptr) {
880  if (!dbname->empty()) {
881  append_with_commas(sql, "default_db = ?");
882  DBMetadata db;
883  if (!SysCatalog::instance().getMetadataForDB(*dbname, db)) {
884  throw runtime_error(string("DEFAULT_DB ") + *dbname + " not found.");
885  }
886  values.push_back(std::to_string(db.dbId));
887  } else {
888  append_with_commas(sql, "default_db = NULL");
889  }
890  }
891  if (can_login != nullptr) {
892  append_with_commas(sql, "can_login = ?");
893  values.push_back(std::to_string(*can_login));
894  }
895 
896  sql = "UPDATE mapd_users SET " + sql + " WHERE userid = ?";
897  values.push_back(std::to_string(userid));
898 
899  sqliteConnector_->query_with_text_params(sql, values);
900  } catch (const std::exception& e) {
901  sqliteConnector_->query("ROLLBACK TRANSACTION");
902  throw;
903  }
904  sqliteConnector_->query("END TRANSACTION");
905 }
906 
907 auto SysCatalog::yieldTransactionStreamer() {
908  return
909  [](auto& db_connector, auto on_success, auto on_failure, auto&&... query_requests) {
910  auto query_runner = [&db_connector](auto&&... query_reqs) {
911  [[gnu::unused]] int throw_away[] = {
912  (db_connector->query_with_text_params(
913  std::forward<decltype(query_reqs)>(query_reqs)),
914  0)...};
915  };
916 
917  db_connector->query("BEGIN TRANSACTION");
918  try {
919  query_runner(std::forward<decltype(query_requests)>(query_requests)...);
920  on_success();
921  } catch (std::exception&) {
922  db_connector->query("ROLLBACK TRANSACTION");
923  on_failure();
924  throw;
925  }
926  db_connector->query("END TRANSACTION");
927  };
928 }
929 
930 void SysCatalog::updateUserRoleName(const std::string& roleName,
931  const std::string& newName) {
933 
934  auto it = granteeMap_.find(to_upper(roleName));
935  if (it != granteeMap_.end()) {
936  it->second->setName(newName);
937  std::swap(granteeMap_[to_upper(newName)], it->second);
938  granteeMap_.erase(it);
939  }
940 }
941 
942 void SysCatalog::renameUser(std::string const& old_name, std::string const& new_name) {
943  using namespace std::string_literals;
946 
947  UserMetadata old_user;
948  if (!getMetadataForUser(old_name, old_user)) {
949  throw std::runtime_error("User " + old_name + " doesn't exist.");
950  }
951 
952  UserMetadata new_user;
953  if (getMetadataForUser(new_name, new_user)) {
954  throw std::runtime_error("User " + new_name + " already exists.");
955  }
956 
957  if (getGrantee(new_name)) {
958  throw runtime_error(
959  "User name " + new_name +
960  " is same as one of existing grantees. User and role names should be unique.");
961  }
962 
963  auto transaction_streamer = yieldTransactionStreamer();
964  auto failure_handler = [] {};
965  auto success_handler = [this, &old_name, &new_name] {
966  updateUserRoleName(old_name, new_name);
967  };
968  auto q1 = {"UPDATE mapd_users SET name=?1 where name=?2;"s, new_name, old_name};
969  auto q2 = {"UPDATE mapd_object_permissions set roleName=?1 WHERE roleName=?2;"s,
970  new_name,
971  old_name};
972  transaction_streamer(sqliteConnector_, success_handler, failure_handler, q1, q2);
973 }
974 
975 void SysCatalog::renameDatabase(std::string const& old_name,
976  std::string const& new_name) {
977  using namespace std::string_literals;
980 
981  DBMetadata new_db;
982  if (getMetadataForDB(new_name, new_db)) {
983  throw std::runtime_error("Database " + new_name + " already exists.");
984  }
985  if (to_upper(new_name) == to_upper(OMNISCI_SYSTEM_CATALOG)) {
986  throw std::runtime_error("Database name " + new_name + "is reserved.");
987  }
988 
989  DBMetadata old_db;
990  if (!getMetadataForDB(old_name, old_db)) {
991  throw std::runtime_error("Database " + old_name + " does not exists.");
992  }
993 
994  Catalog::remove(old_db.dbName);
995 
996  std::string old_catalog_path, new_catalog_path;
997  std::tie(old_catalog_path, new_catalog_path) =
998  duplicateAndRenameCatalog(old_name, new_name);
999 
1000  auto transaction_streamer = yieldTransactionStreamer();
1001  auto failure_handler = [this, new_catalog_path] {
1002  removeCatalogByFullPath(new_catalog_path);
1003  };
1004  auto success_handler = [this, old_catalog_path] {
1005  removeCatalogByFullPath(old_catalog_path);
1006  };
1007 
1008  auto q1 = {"UPDATE mapd_databases SET name=?1 WHERE name=?2;"s, new_name, old_name};
1009  auto q2 = {
1010  "UPDATE mapd_object_permissions SET objectName=?1 WHERE objectNAME=?2 and (objectPermissionsType=?3 or objectId = -1) and dbId=?4;"s,
1011  new_name,
1012  old_name,
1014  std::to_string(old_db.dbId)};
1015 
1016  transaction_streamer(sqliteConnector_, success_handler, failure_handler, q1, q2);
1017 }
1018 
1019 void SysCatalog::createDatabase(const string& name, int owner) {
1020  sys_write_lock write_lock(this);
1022 
1023  DBMetadata db;
1024  if (getMetadataForDB(name, db)) {
1025  throw runtime_error("Database " + name + " already exists.");
1026  }
1027  if (to_upper(name) == to_upper(OMNISCI_SYSTEM_CATALOG)) {
1028  throw runtime_error("Database name " + name + " is reserved.");
1029  }
1030 
1031  std::unique_ptr<SqliteConnector> dbConn(
1032  new SqliteConnector(name, basePath_ + "/mapd_catalogs/"));
1033  // NOTE(max): it's okay to run this in a separate transaction. If we fail later
1034  // we delete the database anyways.
1035  // If we run it in the same transaction as SysCatalog functions, then Catalog
1036  // constructor won't find the tables we have just created.
1037  dbConn->query("BEGIN TRANSACTION");
1038  try {
1039  dbConn->query(
1040  "CREATE TABLE mapd_tables (tableid integer primary key, name text unique, userid "
1041  "integer, ncolumns integer, "
1042  "isview boolean, "
1043  "fragments text, frag_type integer, max_frag_rows integer, max_chunk_size "
1044  "bigint, "
1045  "frag_page_size integer, "
1046  "max_rows bigint, partitions text, shard_column_id integer, shard integer, "
1047  "sort_column_id integer default 0, storage_type text default '',"
1048  "num_shards integer, key_metainfo TEXT, version_num "
1049  "BIGINT DEFAULT 1) ");
1050  dbConn->query(
1051  "CREATE TABLE mapd_columns (tableid integer references mapd_tables, columnid "
1052  "integer, name text, coltype "
1053  "integer, colsubtype integer, coldim integer, colscale integer, is_notnull "
1054  "boolean, compression integer, "
1055  "comp_param integer, size integer, chunks text, is_systemcol boolean, "
1056  "is_virtualcol boolean, virtual_expr "
1057  "text, is_deletedcol boolean, version_num BIGINT, "
1058  "primary key(tableid, columnid), unique(tableid, name))");
1059  dbConn->query(
1060  "CREATE TABLE mapd_views (tableid integer references mapd_tables, sql text)");
1061  dbConn->query(
1062  "CREATE TABLE mapd_dashboards (id integer primary key autoincrement, name text , "
1063  "userid integer references mapd_users, state text, image_hash text, update_time "
1064  "timestamp, "
1065  "metadata text, UNIQUE(userid, name) )");
1066  dbConn->query(
1067  "CREATE TABLE mapd_links (linkid integer primary key, userid integer references "
1068  "mapd_users, "
1069  "link text unique, view_state text, update_time timestamp, view_metadata text)");
1070  dbConn->query(
1071  "CREATE TABLE mapd_dictionaries (dictid integer primary key, name text unique, "
1072  "nbits int, is_shared boolean, "
1073  "refcount int, version_num BIGINT DEFAULT 1)");
1074  dbConn->query(
1075  "CREATE TABLE mapd_logical_to_physical(logical_table_id integer, "
1076  "physical_table_id "
1077  "integer)");
1078  dbConn->query("CREATE TABLE mapd_record_ownership_marker (dummy integer)");
1079  dbConn->query_with_text_params(
1080  "INSERT INTO mapd_record_ownership_marker (dummy) VALUES (?1)",
1081  std::vector<std::string>{std::to_string(owner)});
1082 
1083  if (g_enable_fsi) {
1084  dbConn->query(Catalog::getForeignServerSchema());
1085  dbConn->query(Catalog::getForeignTableSchema());
1086  }
1087  } catch (const std::exception&) {
1088  dbConn->query("ROLLBACK TRANSACTION");
1089  boost::filesystem::remove(basePath_ + "/mapd_catalogs/" + name);
1090  throw;
1091  }
1092  dbConn->query("END TRANSACTION");
1093 
1094  std::shared_ptr<Catalog> cat;
1095  // Now update SysCatalog with privileges and the new database
1096  sqliteConnector_->query("BEGIN TRANSACTION");
1097  try {
1098  sqliteConnector_->query_with_text_param(
1099  "INSERT INTO mapd_databases (name, owner) VALUES (?, " + std::to_string(owner) +
1100  ")",
1101  name);
1102  CHECK(getMetadataForDB(name, db));
1103  cat = Catalog::get(basePath_, db, dataMgr_, string_dict_hosts_, calciteMgr_, true);
1104  if (owner != OMNISCI_ROOT_USER_ID) {
1106  object.loadKey(*cat);
1107  UserMetadata user;
1108  CHECK(getMetadataForUserById(owner, user));
1109  grantAllOnDatabase_unsafe(user.userName, object, *cat);
1110  }
1111  } catch (const std::exception&) {
1112  sqliteConnector_->query("ROLLBACK TRANSACTION");
1113  boost::filesystem::remove(basePath_ + "/mapd_catalogs/" + name);
1114  throw;
1115  }
1116  sqliteConnector_->query("END TRANSACTION");
1117 
1118  if (g_enable_fsi) {
1119  try {
1120  cat->createDefaultServersIfNotExists();
1121  } catch (...) {
1122  boost::filesystem::remove(basePath_ + "/mapd_catalogs/" + name);
1123  throw;
1124  }
1125  }
1126 }
1127 
1128 void SysCatalog::dropDatabase(const DBMetadata& db) {
1129  sys_write_lock write_lock(this);
1131  auto cat =
1132  Catalog::get(basePath_, db, dataMgr_, string_dict_hosts_, calciteMgr_, false);
1133  sqliteConnector_->query("BEGIN TRANSACTION");
1134  try {
1135  // remove this database ID from any users that have it set as their default database
1136  sqliteConnector_->query_with_text_param(
1137  "UPDATE mapd_users SET default_db = NULL WHERE default_db = ?",
1138  std::to_string(db.dbId));
1139  /* revoke object privileges to all tables of the database being dropped */
1140  const auto tables = cat->getAllTableMetadata();
1141  for (const auto table : tables) {
1142  if (table->shard >= 0) {
1143  // skip shards, they're not standalone tables
1144  continue;
1145  }
1146  revokeDBObjectPrivilegesFromAll_unsafe(
1147  DBObject(table->tableName, TableDBObjectType), cat.get());
1148  }
1149  const auto dashboards = cat->getAllDashboardsMetadata();
1150  for (const auto dashboard : dashboards) {
1151  revokeDBObjectPrivilegesFromAll_unsafe(
1152  DBObject(dashboard->dashboardId, DashboardDBObjectType), cat.get());
1153  }
1154  /* revoke object privileges to the database being dropped */
1155  for (const auto& grantee : granteeMap_) {
1156  if (grantee.second->hasAnyPrivilegesOnDb(db.dbId, true)) {
1157  revokeAllOnDatabase_unsafe(grantee.second->getName(), db.dbId, grantee.second);
1158  }
1159  }
1160  sqliteConnector_->query_with_text_param("DELETE FROM mapd_databases WHERE dbid = ?",
1161  std::to_string(db.dbId));
1162  cat->eraseDBData();
1163  Catalog::remove(db.dbName);
1164  } catch (const std::exception&) {
1165  sqliteConnector_->query("ROLLBACK TRANSACTION");
1166  throw;
1167  }
1168  sqliteConnector_->query("END TRANSACTION");
1169 }
1170 
1171 // checkPasswordForUser() with no EE code
1172 bool SysCatalog::checkPasswordForUser(const std::string& passwd,
1173  std::string& name,
1174  UserMetadata& user) {
1175  return checkPasswordForUserImpl(passwd, name, user);
1176 }
1177 
1178 bool SysCatalog::checkPasswordForUserImpl(const std::string& passwd,
1179  std::string& name,
1180  UserMetadata& user) {
1181  if (!getMetadataForUser(name, user)) {
1182  // Check password against some fake hash just to waste time so that response times
1183  // for invalid password and invalid user are similar and a caller can't say the
1184  // difference
1185  char fake_hash[BCRYPT_HASHSIZE];
1186  CHECK(bcrypt_gensalt(-1, fake_hash) == 0);
1187  bcrypt_checkpw(passwd.c_str(), fake_hash);
1188  LOG(WARNING) << "Local login failed";
1189  return false;
1190  }
1191  int pwd_check_result = bcrypt_checkpw(passwd.c_str(), user.passwd_hash.c_str());
1192  // if the check fails there is a good chance that data on disc is broken
1193  CHECK(pwd_check_result >= 0);
1194  return pwd_check_result == 0;
1195 }
1196 
1197 static bool parseUserMetadataFromSQLite(const std::unique_ptr<SqliteConnector>& conn,
1198  UserMetadata& user) {
1199  int numRows = conn->getNumRows();
1200  if (numRows == 0) {
1201  return false;
1202  }
1203  user.userId = conn->getData<int>(0, 0);
1204  user.userName = conn->getData<string>(0, 1);
1205  user.passwd_hash = conn->getData<string>(0, 2);
1206  user.isSuper = conn->getData<bool>(0, 3);
1207  user.defaultDbId = conn->isNull(0, 4) ? -1 : conn->getData<int>(0, 4);
1208  if (conn->isNull(0, 5)) {
1209  LOG(WARNING)
1210  << "User property 'can_login' not set for user " << user.userName
1211  << ". Disabling login ability. Set the users login ability with \"ALTER USER "
1212  << user.userName << " (can_login='true');\".";
1213  }
1214  user.can_login = conn->isNull(0, 5) ? false : conn->getData<bool>(0, 5);
1215  return true;
1216 }
1217 
1218 bool SysCatalog::getMetadataForUser(const string& name, UserMetadata& user) {
1220  sqliteConnector_->query_with_text_param(
1221  "SELECT userid, name, passwd_hash, issuper, default_db, can_login FROM mapd_users "
1222  "WHERE name = ?",
1223  name);
1224  return parseUserMetadataFromSQLite(sqliteConnector_, user);
1225 }
1226 
1227 bool SysCatalog::getMetadataForUserById(const int32_t idIn, UserMetadata& user) {
1229  sqliteConnector_->query_with_text_param(
1230  "SELECT userid, name, passwd_hash, issuper, default_db, can_login FROM mapd_users "
1231  "WHERE userid = ?",
1232  std::to_string(idIn));
1233  return parseUserMetadataFromSQLite(sqliteConnector_, user);
1234 }
1235 
1236 list<DBMetadata> SysCatalog::getAllDBMetadata() {
1238  sqliteConnector_->query("SELECT dbid, name, owner FROM mapd_databases");
1239  int numRows = sqliteConnector_->getNumRows();
1240  list<DBMetadata> db_list;
1241  for (int r = 0; r < numRows; ++r) {
1242  DBMetadata db;
1243  db.dbId = sqliteConnector_->getData<int>(r, 0);
1244  db.dbName = sqliteConnector_->getData<string>(r, 1);
1245  db.dbOwner = sqliteConnector_->getData<int>(r, 2);
1246  db_list.push_back(db);
1247  }
1248  return db_list;
1249 }
1250 
1251 namespace {
1252 
1253 auto get_users(std::unique_ptr<SqliteConnector>& sqliteConnector,
1254  const int32_t dbId = -1) {
1255  sqliteConnector->query("SELECT userid, name, issuper, can_login FROM mapd_users");
1256  int numRows = sqliteConnector->getNumRows();
1257  list<UserMetadata> user_list;
1258  const bool return_all_users = dbId == -1;
1259  auto has_any_privilege = [&return_all_users, &dbId](const std::string& name) {
1260  if (!return_all_users) {
1261  const auto grantee = SysCatalog::instance().getUserGrantee(name);
1262  return grantee ? grantee->hasAnyPrivilegesOnDb(dbId, false) : false;
1263  }
1264  return true;
1265  };
1266  auto add_user = [&user_list, &has_any_privilege](const int32_t id,
1267  const std::string& name,
1268  const bool super,
1269  const bool can_login) {
1270  if (has_any_privilege(name)) {
1271  user_list.emplace_back(id, name, "", super, -1, can_login);
1272  };
1273  };
1274  for (int r = 0; r < numRows; ++r) {
1275  add_user(sqliteConnector->getData<int>(r, 0),
1276  sqliteConnector->getData<string>(r, 1),
1277  sqliteConnector->getData<bool>(r, 2),
1278  sqliteConnector->getData<bool>(r, 3));
1279  }
1280  return user_list;
1281 }
1282 
1283 } // namespace
1284 
1285 list<UserMetadata> SysCatalog::getAllUserMetadata(const int64_t dbId) {
1286  // this call is to return users that have some form of permissions to objects in the db
1287  // sadly mapd_object_permissions table is also misused to manage user roles.
1289  return get_users(sqliteConnector_, dbId);
1290 }
1291 
1292 list<UserMetadata> SysCatalog::getAllUserMetadata() {
1294  return get_users(sqliteConnector_);
1295 }
1296 
1297 void SysCatalog::getMetadataWithDefaultDB(std::string& dbname,
1298  const std::string& username,
1300  UserMetadata& user_meta) {
1301  if (!getMetadataForUser(username, user_meta)) {
1302  throw std::runtime_error("Invalid credentials.");
1303  }
1304 
1305  if (!dbname.empty()) {
1306  if (!getMetadataForDB(dbname, db_meta)) {
1307  throw std::runtime_error("Database name " + dbname + " does not exist.");
1308  }
1309  // loaded the requested database
1310  } else {
1311  if (user_meta.defaultDbId != -1) {
1312  if (!getMetadataForDBById(user_meta.defaultDbId, db_meta)) {
1313  throw std::runtime_error(
1314  "Server error: User #" + std::to_string(user_meta.userId) + " " +
1315  user_meta.userName + " has invalid default_db #" +
1316  std::to_string(user_meta.defaultDbId) + " which does not exist.");
1317  }
1318  dbname = db_meta.dbName;
1319  // loaded the user's default database
1320  } else {
1321  if (!getMetadataForDB(OMNISCI_DEFAULT_DB, db_meta)) {
1322  throw std::runtime_error(std::string("Database ") + OMNISCI_DEFAULT_DB +
1323  " does not exist.");
1324  }
1325  dbname = OMNISCI_DEFAULT_DB;
1326  // loaded the mapd database by default
1327  }
1328  }
1329 }
1330 
1331 bool SysCatalog::getMetadataForDB(const string& name, DBMetadata& db) {
1333  sqliteConnector_->query_with_text_param(
1334  "SELECT dbid, name, owner FROM mapd_databases WHERE name = ?", name);
1335  int numRows = sqliteConnector_->getNumRows();
1336  if (numRows == 0) {
1337  return false;
1338  }
1339  db.dbId = sqliteConnector_->getData<int>(0, 0);
1340  db.dbName = sqliteConnector_->getData<string>(0, 1);
1341  db.dbOwner = sqliteConnector_->getData<int>(0, 2);
1342  return true;
1343 }
1344 
1345 bool SysCatalog::getMetadataForDBById(const int32_t idIn, DBMetadata& db) {
1347  sqliteConnector_->query_with_text_param(
1348  "SELECT dbid, name, owner FROM mapd_databases WHERE dbid = ?",
1349  std::to_string(idIn));
1350  int numRows = sqliteConnector_->getNumRows();
1351  if (numRows == 0) {
1352  return false;
1353  }
1354  db.dbId = sqliteConnector_->getData<int>(0, 0);
1355  db.dbName = sqliteConnector_->getData<string>(0, 1);
1356  db.dbOwner = sqliteConnector_->getData<int>(0, 2);
1357  return true;
1358 }
1359 
1360 DBSummaryList SysCatalog::getDatabaseListForUser(const UserMetadata& user) {
1361  DBSummaryList ret;
1362 
1363  std::list<Catalog_Namespace::DBMetadata> db_list = getAllDBMetadata();
1364  std::list<Catalog_Namespace::UserMetadata> user_list = getAllUserMetadata();
1365 
1366  for (auto d : db_list) {
1367  DBObject dbObject(d.dbName, DatabaseDBObjectType);
1368  dbObject.loadKey();
1370  if (!checkPrivileges(user, std::vector<DBObject>{dbObject})) {
1371  continue;
1372  }
1373  for (auto u : user_list) {
1374  if (d.dbOwner == u.userId) {
1375  ret.emplace_back(DBSummary{d.dbName, u.userName});
1376  break;
1377  }
1378  }
1379  }
1380 
1381  return ret;
1382 }
1383 
1384 void SysCatalog::createDBObject(const UserMetadata& user,
1385  const std::string& objectName,
1387  const Catalog_Namespace::Catalog& catalog,
1388  int32_t objectId) {
1389  sys_write_lock write_lock(this);
1391 
1392  DBObject object =
1393  objectId == -1 ? DBObject(objectName, type) : DBObject(objectId, type);
1394  object.loadKey(catalog);
1395  switch (type) {
1396  case TableDBObjectType:
1397  object.setPrivileges(AccessPrivileges::ALL_TABLE);
1398  break;
1399  case DashboardDBObjectType:
1400  object.setPrivileges(AccessPrivileges::ALL_DASHBOARD);
1401  break;
1402  case ServerDBObjectType:
1403  object.setPrivileges(AccessPrivileges::ALL_SERVER);
1404  break;
1405  default:
1406  object.setPrivileges(AccessPrivileges::ALL_DATABASE);
1407  break;
1408  }
1409  object.setOwner(user.userId);
1410  sqliteConnector_->query("BEGIN TRANSACTION");
1411  try {
1412  if (!user.isSuper) { // no need to grant to suser, has all privs by default
1413  grantDBObjectPrivileges_unsafe(user.userName, object, catalog);
1414  auto* grantee = instance().getUserGrantee(user.userName);
1415  if (!grantee) {
1416  throw runtime_error("User " + user.userName + " does not exist.");
1417  }
1418  grantee->grantPrivileges(object);
1419  }
1420  } catch (std::exception& e) {
1421  sqliteConnector_->query("ROLLBACK TRANSACTION");
1422  throw;
1423  }
1424  sqliteConnector_->query("END TRANSACTION");
1425 }
1426 
1427 void SysCatalog::renameDBObject(const std::string& objectName,
1428  const std::string& newName,
1430  int32_t objectId,
1431  const Catalog_Namespace::Catalog& catalog) {
1432  sys_write_lock write_lock(this);
1433  DBObject new_object(newName, type);
1434  DBObjectKey key;
1435  key.dbId = catalog.getCurrentDB().dbId;
1436  key.objectId = objectId;
1437  key.permissionType = type;
1438  new_object.setObjectKey(key);
1439  auto objdescs =
1440  getMetadataForObject(key.dbId, static_cast<int32_t>(type), key.objectId);
1441  for (auto obj : objdescs) {
1442  Grantee* grnt = getGrantee(obj->roleName);
1443  if (grnt) {
1444  grnt->renameDbObject(new_object);
1445  }
1446  }
1447  renameObjectsInDescriptorMap(new_object, catalog);
1448 }
1449 
1450 void SysCatalog::grantDBObjectPrivilegesBatch_unsafe(
1451  const vector<string>& grantees,
1452  const vector<DBObject>& objects,
1453  const Catalog_Namespace::Catalog& catalog) {
1454  for (const auto& grantee : grantees) {
1455  for (const auto& object : objects) {
1456  grantDBObjectPrivileges_unsafe(grantee, object, catalog);
1457  }
1458  }
1459 }
1460 
1461 // GRANT INSERT ON TABLE payroll_table TO payroll_dept_role;
1462 void SysCatalog::grantDBObjectPrivileges_unsafe(
1463  const std::string& granteeName,
1464  DBObject object,
1465  const Catalog_Namespace::Catalog& catalog) {
1466  object.loadKey(catalog);
1467  if (object.getPrivileges().hasPermission(DatabasePrivileges::ALL) &&
1468  object.getObjectKey().permissionType == DatabaseDBObjectType) {
1469  return grantAllOnDatabase_unsafe(granteeName, object, catalog);
1470  }
1471 
1472  sys_write_lock write_lock(this);
1473 
1474  UserMetadata user_meta;
1475  if (instance().getMetadataForUser(granteeName, user_meta)) {
1476  if (user_meta.isSuper) {
1477  // super doesn't have explicit privileges so nothing to do
1478  return;
1479  }
1480  }
1481  auto* grantee = instance().getGrantee(granteeName);
1482  if (!grantee) {
1483  throw runtime_error("Request to grant privileges to " + granteeName +
1484  " failed because role or user with this name does not exist.");
1485  }
1486  grantee->grantPrivileges(object);
1487 
1488  /* apply grant privileges statement to sqlite DB */
1489  std::vector<std::string> objectKey = object.toString();
1490  object.resetPrivileges();
1491  grantee->getPrivileges(object, true);
1492 
1495  sqliteConnector_, granteeName, grantee->isUser(), object);
1496  updateObjectDescriptorMap(granteeName, object, grantee->isUser(), catalog);
1497 }
1498 
1499 void SysCatalog::grantAllOnDatabase_unsafe(const std::string& roleName,
1500  DBObject& object,
1501  const Catalog_Namespace::Catalog& catalog) {
1502  // It's a separate use case because it's easier for implementation to convert ALL ON
1503  // DATABASE into ALL ON DASHBOARDS, ALL ON VIEWS and ALL ON TABLES
1504  // Add DB Access privileges
1505  DBObject tmp_object = object;
1508  grantDBObjectPrivileges_unsafe(roleName, tmp_object, catalog);
1511  grantDBObjectPrivileges_unsafe(roleName, tmp_object, catalog);
1514  grantDBObjectPrivileges_unsafe(roleName, tmp_object, catalog);
1516  tmp_object.setPermissionType(ViewDBObjectType);
1517  grantDBObjectPrivileges_unsafe(roleName, tmp_object, catalog);
1518 
1519  if (g_enable_fsi) {
1522  grantDBObjectPrivileges_unsafe(roleName, tmp_object, catalog);
1523  }
1524 
1527  grantDBObjectPrivileges_unsafe(roleName, tmp_object, catalog);
1528  return;
1529 }
1530 
1531 void SysCatalog::revokeDBObjectPrivilegesBatch_unsafe(
1532  const vector<string>& grantees,
1533  const vector<DBObject>& objects,
1534  const Catalog_Namespace::Catalog& catalog) {
1535  for (const auto& grantee : grantees) {
1536  for (const auto& object : objects) {
1537  revokeDBObjectPrivileges_unsafe(grantee, object, catalog);
1538  }
1539  }
1540 }
1541 
1542 // REVOKE INSERT ON TABLE payroll_table FROM payroll_dept_role;
1543 void SysCatalog::revokeDBObjectPrivileges_unsafe(
1544  const std::string& granteeName,
1545  DBObject object,
1546  const Catalog_Namespace::Catalog& catalog) {
1547  sys_write_lock write_lock(this);
1548 
1549  UserMetadata user_meta;
1550  if (instance().getMetadataForUser(granteeName, user_meta)) {
1551  if (user_meta.isSuper) {
1552  // super doesn't have explicit privileges so nothing to do
1553  return;
1554  }
1555  }
1556  auto* grantee = getGrantee(granteeName);
1557  if (!grantee) {
1558  throw runtime_error("Request to revoke privileges from " + granteeName +
1559  " failed because role or user with this name does not exist.");
1560  }
1561  object.loadKey(catalog);
1562 
1563  if (object.getPrivileges().hasPermission(DatabasePrivileges::ALL) &&
1564  object.getObjectKey().permissionType == DatabaseDBObjectType) {
1565  return revokeAllOnDatabase_unsafe(granteeName, object.getObjectKey().dbId, grantee);
1566  }
1567 
1568  auto ret_object = grantee->revokePrivileges(object);
1569  if (ret_object) {
1572  sqliteConnector_, granteeName, grantee->isUser(), *ret_object);
1573  updateObjectDescriptorMap(granteeName, *ret_object, grantee->isUser(), catalog);
1574  } else {
1576  deleteObjectPrivileges(sqliteConnector_, granteeName, grantee->isUser(), object);
1577  deleteObjectDescriptorMap(granteeName, object, catalog);
1578  }
1579 }
1580 
1581 void SysCatalog::revokeAllOnDatabase_unsafe(const std::string& roleName,
1582  int32_t dbId,
1583  Grantee* grantee) {
1585  sqliteConnector_->query_with_text_params(
1586  "DELETE FROM mapd_object_permissions WHERE roleName = ?1 and dbId = ?2",
1587  std::vector<std::string>{roleName, std::to_string(dbId)});
1588  grantee->revokeAllOnDatabase(dbId);
1589  for (auto d = objectDescriptorMap_.begin(); d != objectDescriptorMap_.end();) {
1590  if (d->second->roleName == roleName && d->second->dbId == dbId) {
1591  delete d->second;
1592  d = objectDescriptorMap_.erase(d);
1593  } else {
1594  d++;
1595  }
1596  }
1597 }
1598 
1599 void SysCatalog::revokeDBObjectPrivilegesFromAll_unsafe(DBObject dbObject,
1600  Catalog* catalog) {
1601  sys_write_lock write_lock(this);
1602  dbObject.loadKey(*catalog);
1603  auto privs = (dbObject.getObjectKey().permissionType == TableDBObjectType)
1608  dbObject.setPrivileges(privs);
1609  for (const auto& grantee : granteeMap_) {
1610  if (grantee.second->findDbObject(dbObject.getObjectKey(), true)) {
1611  revokeDBObjectPrivileges_unsafe(grantee.second->getName(), dbObject, *catalog);
1612  }
1613  }
1614 }
1615 
1616 bool SysCatalog::verifyDBObjectOwnership(const UserMetadata& user,
1617  DBObject object,
1618  const Catalog_Namespace::Catalog& catalog) {
1619  sys_read_lock read_lock(this);
1620 
1621  auto* grantee = instance().getUserGrantee(user.userName);
1622  if (grantee) {
1623  object.loadKey(catalog);
1624  auto* found_object = grantee->findDbObject(object.getObjectKey(), false);
1625  if (found_object && found_object->getOwner() == user.userId) {
1626  return true;
1627  }
1628  }
1629  return false;
1630 }
1631 
1632 void SysCatalog::changeDBObjectOwnership(const UserMetadata& new_owner,
1633  const UserMetadata& previous_owner,
1634  DBObject object,
1635  const Catalog_Namespace::Catalog& catalog,
1636  bool revoke_privileges) {
1637  sys_write_lock write_lock(this);
1639  object.loadKey(catalog);
1640  switch (object.getType()) {
1641  case TableDBObjectType:
1642  object.setPrivileges(AccessPrivileges::ALL_TABLE);
1643  break;
1644  case DashboardDBObjectType:
1645  object.setPrivileges(AccessPrivileges::ALL_DASHBOARD);
1646  break;
1647  case ServerDBObjectType:
1648  object.setPrivileges(AccessPrivileges::ALL_SERVER);
1649  break;
1650  case DatabaseDBObjectType:
1651  object.setPrivileges(AccessPrivileges::ALL_DATABASE);
1652  break;
1653  case ViewDBObjectType:
1654  object.setPrivileges(AccessPrivileges::ALL_VIEW);
1655  break;
1656  default:
1657  UNREACHABLE(); // unkown object type
1658  break;
1659  }
1660  sqliteConnector_->query("BEGIN TRANSACTION");
1661  try {
1662  if (!new_owner.isSuper) { // no need to grant to suser, has all privs by default
1663  grantDBObjectPrivileges_unsafe(new_owner.userName, object, catalog);
1664  }
1665  if (!previous_owner.isSuper && revoke_privileges) { // no need to revoke from suser
1666  revokeDBObjectPrivileges_unsafe(previous_owner.userName, object, catalog);
1667  }
1668  } catch (std::exception& e) {
1669  sqliteConnector_->query("ROLLBACK TRANSACTION");
1670  throw;
1671  }
1672  sqliteConnector_->query("END TRANSACTION");
1673  object.setOwner(new_owner.userId); // change owner if no exceptions happen
1674 }
1675 
1676 void SysCatalog::getDBObjectPrivileges(const std::string& granteeName,
1677  DBObject& object,
1678  const Catalog_Namespace::Catalog& catalog) const {
1679  sys_read_lock read_lock(this);
1680  UserMetadata user_meta;
1681 
1682  if (instance().getMetadataForUser(granteeName, user_meta)) {
1683  if (user_meta.isSuper) {
1684  throw runtime_error(
1685  "Request to show privileges from " + granteeName +
1686  " failed because user is super user and has all privileges by default.");
1687  }
1688  }
1689  auto* grantee = instance().getGrantee(granteeName);
1690  if (!grantee) {
1691  throw runtime_error("Request to show privileges for " + granteeName +
1692  " failed because role or user with this name does not exist.");
1693  }
1694  object.loadKey(catalog);
1695  grantee->getPrivileges(object, true);
1696 }
1697 
1698 void SysCatalog::createRole_unsafe(const std::string& roleName,
1699  const bool& userPrivateRole) {
1700  sys_write_lock write_lock(this);
1701 
1702  auto* grantee = getGrantee(roleName);
1703  if (grantee) {
1704  throw std::runtime_error("CREATE ROLE " + roleName +
1705  " failed because grantee with this name already exists.");
1706  }
1707  if (userPrivateRole) {
1708  grantee = new User(roleName);
1709  } else {
1710  grantee = new Role(roleName);
1711  }
1712  granteeMap_[to_upper(roleName)] = grantee;
1713 
1714  // NOTE (max): Why create an empty privileges record for a role?
1715  /* grant none privileges to this role and add it to sqlite DB */
1717  DBObjectKey objKey;
1718  // 0 is an id that does not exist
1719  objKey.dbId = 0;
1721  dbObject.setObjectKey(objKey);
1722  grantee->grantPrivileges(dbObject);
1723 
1725  insertOrUpdateObjectPrivileges(sqliteConnector_, roleName, userPrivateRole, dbObject);
1726 }
1727 
1728 void SysCatalog::dropRole_unsafe(const std::string& roleName) {
1729  sys_write_lock write_lock(this);
1730 
1731  // it may very well be a user "role", so keep it generic
1732  auto* rl = getGrantee(roleName);
1733  if (rl) { // admin super user may not exist in roles
1734  delete rl;
1735  }
1736  granteeMap_.erase(to_upper(roleName));
1737 
1739  sqliteConnector_->query_with_text_param("DELETE FROM mapd_roles WHERE roleName = ?",
1740  roleName);
1741  sqliteConnector_->query_with_text_param(
1742  "DELETE FROM mapd_object_permissions WHERE roleName = ?", roleName);
1743 }
1744 
1745 void SysCatalog::grantRoleBatch_unsafe(const std::vector<std::string>& roles,
1746  const std::vector<std::string>& grantees) {
1747  for (const auto& role : roles) {
1748  for (const auto& grantee : grantees) {
1749  grantRole_unsafe(role, grantee);
1750  }
1751  }
1752 }
1753 
1754 // GRANT ROLE payroll_dept_role TO joe;
1755 void SysCatalog::grantRole_unsafe(const std::string& roleName,
1756  const std::string& granteeName) {
1757  auto* rl = getRoleGrantee(roleName);
1758  if (!rl) {
1759  throw runtime_error("Request to grant role " + roleName +
1760  " failed because role with this name does not exist.");
1761  }
1762  auto* grantee = getGrantee(granteeName);
1763  if (!grantee) {
1764  throw runtime_error("Request to grant role " + roleName + " failed because grantee " +
1765  granteeName + " does not exist.");
1766  }
1767  sys_write_lock write_lock(this);
1768  if (!grantee->hasRole(rl, true)) {
1769  grantee->grantRole(rl);
1771  sqliteConnector_->query_with_text_params(
1772  "INSERT INTO mapd_roles(roleName, userName) VALUES (?, ?)",
1773  std::vector<std::string>{rl->getName(), grantee->getName()});
1774  }
1775 }
1776 
1777 void SysCatalog::revokeRoleBatch_unsafe(const std::vector<std::string>& roles,
1778  const std::vector<std::string>& grantees) {
1779  for (const auto& role : roles) {
1780  for (const auto& grantee : grantees) {
1781  revokeRole_unsafe(role, grantee);
1782  }
1783  }
1784 }
1785 
1786 // REVOKE ROLE payroll_dept_role FROM joe;
1787 void SysCatalog::revokeRole_unsafe(const std::string& roleName,
1788  const std::string& granteeName) {
1789  auto* rl = getRoleGrantee(roleName);
1790  if (!rl) {
1791  throw runtime_error("Request to revoke role " + roleName +
1792  " failed because role with this name does not exist.");
1793  }
1794  auto* grantee = getGrantee(granteeName);
1795  if (!grantee) {
1796  throw runtime_error("Request to revoke role from " + granteeName +
1797  " failed because grantee with this name does not exist.");
1798  }
1799  sys_write_lock write_lock(this);
1800  grantee->revokeRole(rl);
1802  sqliteConnector_->query_with_text_params(
1803  "DELETE FROM mapd_roles WHERE roleName = ? AND userName = ?",
1804  std::vector<std::string>{rl->getName(), grantee->getName()});
1805 }
1806 
1807 // Update or add element in ObjectRoleDescriptorMap
1808 void SysCatalog::updateObjectDescriptorMap(const std::string& roleName,
1809  DBObject& object,
1810  bool roleType,
1812  bool present = false;
1813  auto privs = object.getPrivileges();
1814  sys_write_lock write_lock(this);
1815  auto range = objectDescriptorMap_.equal_range(
1816  std::to_string(cat.getCurrentDB().dbId) + ":" +
1817  std::to_string(object.getObjectKey().permissionType) + ":" +
1818  std::to_string(object.getObjectKey().objectId));
1819  for (auto d = range.first; d != range.second; ++d) {
1820  if (d->second->roleName == roleName) {
1821  // overwrite permissions
1822  d->second->privs = privs;
1823  present = true;
1824  }
1825  }
1826  if (!present) {
1828  od->roleName = roleName;
1829  od->roleType = roleType;
1830  od->objectType = object.getObjectKey().permissionType;
1831  od->dbId = object.getObjectKey().dbId;
1832  od->objectId = object.getObjectKey().objectId;
1833  od->privs = object.getPrivileges();
1834  od->objectOwnerId = object.getOwner();
1835  od->objectName = object.getName();
1836  objectDescriptorMap_.insert(ObjectRoleDescriptorMap::value_type(
1837  std::to_string(od->dbId) + ":" + std::to_string(od->objectType) + ":" +
1838  std::to_string(od->objectId),
1839  od));
1840  }
1841 }
1842 
1843 // rename object descriptors
1844 void SysCatalog::renameObjectsInDescriptorMap(DBObject& object,
1846  sys_write_lock write_lock(this);
1848  auto range = objectDescriptorMap_.equal_range(
1849  std::to_string(cat.getCurrentDB().dbId) + ":" +
1850  std::to_string(object.getObjectKey().permissionType) + ":" +
1851  std::to_string(object.getObjectKey().objectId));
1852  for (auto d = range.first; d != range.second; ++d) {
1853  // rename object
1854  d->second->objectName = object.getName();
1855  }
1856 
1857  sqliteConnector_->query("BEGIN TRANSACTION");
1858  try {
1859  sqliteConnector_->query_with_text_params(
1860  "UPDATE mapd_object_permissions SET objectName = ?1 WHERE "
1861  "dbId = ?2 AND objectId = ?3",
1862  std::vector<std::string>{object.getName(),
1864  std::to_string(object.getObjectKey().objectId)});
1865  } catch (const std::exception& e) {
1866  sqliteConnector_->query("ROLLBACK TRANSACTION");
1867  throw;
1868  }
1869  sqliteConnector_->query("END TRANSACTION");
1870 }
1871 
1872 // Remove user/role from ObjectRoleDescriptorMap
1873 void SysCatalog::deleteObjectDescriptorMap(const std::string& roleName) {
1874  sys_write_lock write_lock(this);
1875 
1876  for (auto d = objectDescriptorMap_.begin(); d != objectDescriptorMap_.end();) {
1877  if (d->second->roleName == roleName) {
1878  delete d->second;
1879  d = objectDescriptorMap_.erase(d);
1880  } else {
1881  d++;
1882  }
1883  }
1884 }
1885 
1886 // Remove element from ObjectRoleDescriptorMap
1887 void SysCatalog::deleteObjectDescriptorMap(const std::string& roleName,
1888  DBObject& object,
1890  sys_write_lock write_lock(this);
1891  auto range = objectDescriptorMap_.equal_range(
1892  std::to_string(cat.getCurrentDB().dbId) + ":" +
1893  std::to_string(object.getObjectKey().permissionType) + ":" +
1894  std::to_string(object.getObjectKey().objectId));
1895  for (auto d = range.first; d != range.second;) {
1896  // remove the entry
1897  if (d->second->roleName == roleName) {
1898  delete d->second;
1899  d = objectDescriptorMap_.erase(d);
1900  } else {
1901  d++;
1902  }
1903  }
1904 }
1905 
1906 bool SysCatalog::hasAnyPrivileges(const UserMetadata& user,
1907  std::vector<DBObject>& privObjects) {
1908  sys_read_lock read_lock(this);
1909  if (user.isSuper) {
1910  return true;
1911  }
1912  auto* user_rl = instance().getUserGrantee(user.userName);
1913  if (!user_rl) {
1914  throw runtime_error("User " + user.userName + " does not exist.");
1915  }
1916  for (std::vector<DBObject>::iterator objectIt = privObjects.begin();
1917  objectIt != privObjects.end();
1918  ++objectIt) {
1919  if (!user_rl->hasAnyPrivileges(*objectIt, false)) {
1920  return false;
1921  }
1922  }
1923  return true;
1924 }
1925 
1926 bool SysCatalog::checkPrivileges(const UserMetadata& user,
1927  const std::vector<DBObject>& privObjects) const {
1928  sys_read_lock read_lock(this);
1929  if (user.isSuper) {
1930  return true;
1931  }
1932 
1933  auto* user_rl = instance().getUserGrantee(user.userName);
1934  if (!user_rl) {
1935  throw runtime_error("User " + user.userName + " does not exist.");
1936  }
1937  for (auto& object : privObjects) {
1938  if (!user_rl->checkPrivileges(object)) {
1939  return false;
1940  }
1941  }
1942  return true;
1943 }
1944 
1945 bool SysCatalog::checkPrivileges(const std::string& userName,
1946  const std::vector<DBObject>& privObjects) const {
1947  UserMetadata user;
1948  if (!instance().getMetadataForUser(userName, user)) {
1949  throw runtime_error("Request to check privileges for user " + userName +
1950  " failed because user with this name does not exist.");
1951  }
1952  return (checkPrivileges(user, privObjects));
1953 }
1954 
1955 Grantee* SysCatalog::getGrantee(const std::string& name) const {
1956  sys_read_lock read_lock(this);
1957  auto grantee = granteeMap_.find(to_upper(name));
1958  if (grantee == granteeMap_.end()) { // check to make sure role exists
1959  return nullptr;
1960  }
1961  return grantee->second; // returns pointer to role
1962 }
1963 
1964 Role* SysCatalog::getRoleGrantee(const std::string& name) const {
1965  return dynamic_cast<Role*>(getGrantee(name));
1966 }
1967 
1968 User* SysCatalog::getUserGrantee(const std::string& name) const {
1969  return dynamic_cast<User*>(getGrantee(name));
1970 }
1971 
1972 std::vector<ObjectRoleDescriptor*>
1973 SysCatalog::getMetadataForObject(int32_t dbId, int32_t dbType, int32_t objectId) const {
1974  sys_read_lock read_lock(this);
1975  std::vector<ObjectRoleDescriptor*> objectsList;
1976 
1977  auto range = objectDescriptorMap_.equal_range(std::to_string(dbId) + ":" +
1978  std::to_string(dbType) + ":" +
1979  std::to_string(objectId));
1980  for (auto d = range.first; d != range.second; ++d) {
1981  objectsList.push_back(d->second);
1982  }
1983  return objectsList; // return pointers to objects
1984 }
1985 
1986 bool SysCatalog::isRoleGrantedToGrantee(const std::string& granteeName,
1987  const std::string& roleName,
1988  bool only_direct) const {
1989  sys_read_lock read_lock(this);
1990  if (roleName == granteeName) {
1991  return true;
1992  }
1993  bool is_role_granted = false;
1994  auto* target_role = instance().getRoleGrantee(roleName);
1995  auto has_role = [&](auto grantee_rl) {
1996  is_role_granted = target_role && grantee_rl->hasRole(target_role, only_direct);
1997  };
1998  if (auto* user_role = instance().getUserGrantee(granteeName); user_role) {
1999  has_role(user_role);
2000  } else if (auto* role = instance().getRoleGrantee(granteeName); role) {
2001  has_role(role);
2002  } else {
2003  CHECK(false);
2004  }
2005  return is_role_granted;
2006 }
2007 
2008 bool SysCatalog::isDashboardSystemRole(const std::string& roleName) {
2009  return boost::algorithm::ends_with(roleName, SYSTEM_ROLE_TAG);
2010 }
2011 
2012 std::vector<std::string> SysCatalog::getRoles(const std::string& userName,
2013  const int32_t dbId) {
2015  std::string sql =
2016  "SELECT DISTINCT roleName FROM mapd_object_permissions WHERE "
2017  "objectPermissions<>0 "
2018  "AND roleType=0 AND dbId=" +
2019  std::to_string(dbId);
2020  sqliteConnector_->query(sql);
2021  int numRows = sqliteConnector_->getNumRows();
2022  std::vector<std::string> roles(0);
2023  for (int r = 0; r < numRows; ++r) {
2024  auto roleName = sqliteConnector_->getData<string>(r, 0);
2025  if (isRoleGrantedToGrantee(userName, roleName, false) &&
2026  !isDashboardSystemRole(roleName)) {
2027  roles.push_back(roleName);
2028  }
2029  }
2030  return roles;
2031 }
2032 
2033 std::vector<std::string> SysCatalog::getRoles(bool userPrivateRole,
2034  bool isSuper,
2035  const std::string& userName) {
2036  sys_read_lock read_lock(this);
2037  std::vector<std::string> roles;
2038  for (auto& grantee : granteeMap_) {
2039  if (!userPrivateRole && grantee.second->isUser()) {
2040  continue;
2041  }
2042  if (!isSuper && !isRoleGrantedToGrantee(userName, grantee.second->getName(), false)) {
2043  continue;
2044  }
2045  if (isDashboardSystemRole(grantee.second->getName())) {
2046  continue;
2047  }
2048  roles.push_back(grantee.second->getName());
2049  }
2050  return roles;
2051 }
2052 
2053 void SysCatalog::revokeDashboardSystemRole(const std::string roleName,
2054  const std::vector<std::string> grantees) {
2055  auto* rl = getRoleGrantee(roleName);
2056  for (auto granteeName : grantees) {
2057  const auto* grantee = SysCatalog::instance().getGrantee(granteeName);
2058  if (rl && grantee->hasRole(rl, true)) {
2059  // Grantees existence have been already validated
2060  SysCatalog::instance().revokeRole(roleName, granteeName);
2061  }
2062  }
2063 }
2064 
2065 void SysCatalog::buildRoleMap() {
2066  sys_write_lock write_lock(this);
2068  string roleQuery(
2069  "SELECT roleName, roleType, objectPermissionsType, dbId, objectId, "
2070  "objectPermissions, objectOwnerId, objectName "
2071  "from mapd_object_permissions");
2072  sqliteConnector_->query(roleQuery);
2073  size_t numRows = sqliteConnector_->getNumRows();
2074  std::vector<std::string> objectKeyStr(4);
2075  DBObjectKey objectKey;
2076  AccessPrivileges privs;
2077  bool userPrivateRole(false);
2078  for (size_t r = 0; r < numRows; ++r) {
2079  std::string roleName = sqliteConnector_->getData<string>(r, 0);
2080  userPrivateRole = sqliteConnector_->getData<bool>(r, 1);
2081  DBObjectType permissionType =
2082  static_cast<DBObjectType>(sqliteConnector_->getData<int>(r, 2));
2083  objectKeyStr[0] = sqliteConnector_->getData<string>(r, 2);
2084  objectKeyStr[1] = sqliteConnector_->getData<string>(r, 3);
2085  objectKeyStr[2] = sqliteConnector_->getData<string>(r, 4);
2086  objectKey = DBObjectKey::fromString(objectKeyStr, permissionType);
2087  privs.privileges = sqliteConnector_->getData<int>(r, 5);
2088  int32_t owner = sqliteConnector_->getData<int>(r, 6);
2089  std::string name = sqliteConnector_->getData<string>(r, 7);
2090 
2091  DBObject dbObject(objectKey, privs, owner);
2092  dbObject.setName(name);
2093  if (-1 == objectKey.objectId) {
2094  dbObject.setObjectType(DBObjectType::DatabaseDBObjectType);
2095  } else {
2096  dbObject.setObjectType(permissionType);
2097  }
2098 
2099  auto* rl = getGrantee(roleName);
2100  if (!rl) {
2101  if (userPrivateRole) {
2102  rl = new User(roleName);
2103  } else {
2104  rl = new Role(roleName);
2105  }
2106  granteeMap_[to_upper(roleName)] = rl;
2107  }
2108  rl->grantPrivileges(dbObject);
2109  }
2110 }
2111 
2112 void SysCatalog::populateRoleDbObjects(const std::vector<DBObject>& objects) {
2113  sys_write_lock write_lock(this);
2115  sqliteConnector_->query("BEGIN TRANSACTION");
2116  try {
2117  for (auto dbobject : objects) {
2118  UserMetadata user;
2119  CHECK(getMetadataForUserById(dbobject.getOwner(), user));
2120  auto* grantee = getUserGrantee(user.userName);
2121  if (grantee) {
2123  sqliteConnector_, grantee->getName(), true, dbobject);
2124  grantee->grantPrivileges(dbobject);
2125  }
2126  }
2127 
2128  } catch (const std::exception& e) {
2129  sqliteConnector_->query("ROLLBACK TRANSACTION");
2130  throw;
2131  }
2132  sqliteConnector_->query("END TRANSACTION");
2133 }
2134 
2135 void SysCatalog::buildUserRoleMap() {
2136  sys_write_lock write_lock(this);
2138  std::vector<std::pair<std::string, std::string>> granteeRooles;
2139  string userRoleQuery("SELECT roleName, userName from mapd_roles");
2140  sqliteConnector_->query(userRoleQuery);
2141  size_t numRows = sqliteConnector_->getNumRows();
2142  for (size_t r = 0; r < numRows; ++r) {
2143  std::string roleName = sqliteConnector_->getData<string>(r, 0);
2144  std::string userName = sqliteConnector_->getData<string>(r, 1);
2145  // required for declared nomenclature before v4.0.0
2146  if ((boost::equals(roleName, "mapd_default_suser_role") &&
2147  boost::equals(userName, OMNISCI_ROOT_USER)) ||
2148  (boost::equals(roleName, "mapd_default_user_role") &&
2149  !boost::equals(userName, "mapd_default_user_role"))) {
2150  // grouprole already exists with roleName==userName in mapd_roles table
2151  // ignore duplicate instances of userRole which exists before v4.0.0
2152  continue;
2153  }
2154  auto* rl = getGrantee(roleName);
2155  if (!rl) {
2156  throw runtime_error("Data inconsistency when building role map. Role " + roleName +
2157  " from db not found in the map.");
2158  }
2159  std::pair<std::string, std::string> roleVecElem(roleName, userName);
2160  granteeRooles.push_back(roleVecElem);
2161  }
2162 
2163  for (size_t i = 0; i < granteeRooles.size(); i++) {
2164  std::string roleName = granteeRooles[i].first;
2165  std::string granteeName = granteeRooles[i].second;
2166  auto* grantee = getGrantee(granteeName);
2167  if (!grantee) {
2168  throw runtime_error("Data inconsistency when building role map. Grantee " +
2169  granteeName + " not found in the map.");
2170  }
2171  if (granteeName == roleName) {
2172  continue;
2173  }
2174  Role* rl = dynamic_cast<Role*>(getGrantee(roleName));
2175  if (!rl) {
2176  throw runtime_error("Data inconsistency when building role map. Role " + roleName +
2177  " not found in the map.");
2178  }
2179  grantee->grantRole(rl);
2180  }
2181 }
2182 
2183 void SysCatalog::buildObjectDescriptorMap() {
2184  sys_write_lock write_lock(this);
2186  string objectQuery(
2187  "SELECT roleName, roleType, objectPermissionsType, dbId, objectId, "
2188  "objectPermissions, objectOwnerId, objectName "
2189  "from mapd_object_permissions");
2190  sqliteConnector_->query(objectQuery);
2191  size_t numRows = sqliteConnector_->getNumRows();
2192  for (size_t r = 0; r < numRows; ++r) {
2194  od->roleName = sqliteConnector_->getData<string>(r, 0);
2195  od->roleType = sqliteConnector_->getData<bool>(r, 1);
2196  od->objectType = sqliteConnector_->getData<int>(r, 2);
2197  od->dbId = sqliteConnector_->getData<int>(r, 3);
2198  od->objectId = sqliteConnector_->getData<int>(r, 4);
2199  od->privs.privileges = sqliteConnector_->getData<int>(r, 5);
2200  od->objectOwnerId = sqliteConnector_->getData<int>(r, 6);
2201  od->objectName = sqliteConnector_->getData<string>(r, 7);
2202  objectDescriptorMap_.insert(ObjectRoleDescriptorMap::value_type(
2203  std::to_string(od->dbId) + ":" + std::to_string(od->objectType) + ":" +
2204  std::to_string(od->objectId),
2205  od));
2206  }
2207 }
2208 
2209 template <typename F, typename... Args>
2210 void SysCatalog::execInTransaction(F&& f, Args&&... args) {
2211  sys_write_lock write_lock(this);
2213  sqliteConnector_->query("BEGIN TRANSACTION");
2214  try {
2215  (this->*f)(std::forward<Args>(args)...);
2216  } catch (std::exception&) {
2217  sqliteConnector_->query("ROLLBACK TRANSACTION");
2218  throw;
2219  }
2220  sqliteConnector_->query("END TRANSACTION");
2221 }
2222 
2223 void SysCatalog::createRole(const std::string& roleName, const bool& userPrivateRole) {
2224  execInTransaction(&SysCatalog::createRole_unsafe, roleName, userPrivateRole);
2225 }
2226 
2227 void SysCatalog::dropRole(const std::string& roleName) {
2228  execInTransaction(&SysCatalog::dropRole_unsafe, roleName);
2229 }
2230 
2231 void SysCatalog::grantRoleBatch(const std::vector<std::string>& roles,
2232  const std::vector<std::string>& grantees) {
2233  execInTransaction(&SysCatalog::grantRoleBatch_unsafe, roles, grantees);
2234 }
2235 
2236 void SysCatalog::grantRole(const std::string& role, const std::string& grantee) {
2237  execInTransaction(&SysCatalog::grantRole_unsafe, role, grantee);
2238 }
2239 
2240 void SysCatalog::revokeRoleBatch(const std::vector<std::string>& roles,
2241  const std::vector<std::string>& grantees) {
2242  execInTransaction(&SysCatalog::revokeRoleBatch_unsafe, roles, grantees);
2243 }
2244 
2245 void SysCatalog::revokeRole(const std::string& role, const std::string& grantee) {
2246  execInTransaction(&SysCatalog::revokeRole_unsafe, role, grantee);
2247 }
2248 
2249 void SysCatalog::grantDBObjectPrivileges(const string& grantee,
2250  const DBObject& object,
2251  const Catalog_Namespace::Catalog& catalog) {
2252  execInTransaction(
2253  &SysCatalog::grantDBObjectPrivileges_unsafe, grantee, object, catalog);
2254 }
2255 
2256 void SysCatalog::grantDBObjectPrivilegesBatch(const vector<string>& grantees,
2257  const vector<DBObject>& objects,
2258  const Catalog_Namespace::Catalog& catalog) {
2259  execInTransaction(
2260  &SysCatalog::grantDBObjectPrivilegesBatch_unsafe, grantees, objects, catalog);
2261 }
2262 
2263 void SysCatalog::revokeDBObjectPrivileges(const string& grantee,
2264  const DBObject& object,
2265  const Catalog_Namespace::Catalog& catalog) {
2266  execInTransaction(
2267  &SysCatalog::revokeDBObjectPrivileges_unsafe, grantee, object, catalog);
2268 }
2269 
2270 void SysCatalog::revokeDBObjectPrivilegesBatch(
2271  const vector<string>& grantees,
2272  const vector<DBObject>& objects,
2273  const Catalog_Namespace::Catalog& catalog) {
2274  execInTransaction(
2275  &SysCatalog::revokeDBObjectPrivilegesBatch_unsafe, grantees, objects, catalog);
2276 }
2277 
2278 void SysCatalog::revokeDBObjectPrivilegesFromAll(DBObject object, Catalog* catalog) {
2279  execInTransaction(&SysCatalog::revokeDBObjectPrivilegesFromAll_unsafe, object, catalog);
2280 }
2281 
2282 void SysCatalog::syncUserWithRemoteProvider(const std::string& user_name,
2283  std::vector<std::string> idp_roles,
2284  bool* is_super) {
2285  UserMetadata user_meta;
2286  bool is_super_user = is_super ? *is_super : false;
2287  if (!getMetadataForUser(user_name, user_meta)) {
2288  createUser(user_name, generate_random_string(72), is_super_user, "", true);
2289  LOG(INFO) << "User " << user_name << " has been created by remote identity provider"
2290  << " with IS_SUPER = " << (is_super_user ? "'TRUE'" : "'FALSE'");
2291  } else if (is_super && is_super_user != user_meta.isSuper) {
2292  alterUser(user_meta.userId, nullptr, is_super, nullptr, nullptr);
2293  LOG(INFO) << "IS_SUPER for user " << user_name << " has been changed to "
2294  << (is_super_user ? "TRUE" : "FALSE") << " by remote identity provider";
2295  }
2296  std::vector<std::string> current_roles = {};
2297  auto* user_rl = getUserGrantee(user_name);
2298  if (user_rl) {
2299  current_roles = user_rl->getRoles();
2300  }
2301  std::transform(
2302  current_roles.begin(), current_roles.end(), current_roles.begin(), to_upper);
2303  std::transform(idp_roles.begin(), idp_roles.end(), idp_roles.begin(), to_upper);
2304  std::list<std::string> roles_revoked, roles_granted;
2305  // first remove obsolete ones
2306  for (auto& current_role_name : current_roles) {
2307  if (std::find(idp_roles.begin(), idp_roles.end(), current_role_name) ==
2308  idp_roles.end()) {
2309  revokeRole(current_role_name, user_name);
2310  roles_revoked.push_back(current_role_name);
2311  }
2312  }
2313  for (auto& role_name : idp_roles) {
2314  if (std::find(current_roles.begin(), current_roles.end(), role_name) ==
2315  current_roles.end()) {
2316  auto* rl = getRoleGrantee(role_name);
2317  if (rl) {
2318  grantRole(role_name, user_name);
2319  roles_granted.push_back(role_name);
2320  } else {
2321  LOG(WARNING) << "Error synchronizing roles for user " << user_name << ": role "
2322  << role_name << " does not exist";
2323  }
2324  }
2325  }
2326  if (roles_granted.empty() && roles_revoked.empty()) {
2327  LOG(INFO) << "Roles for user " << user_name
2328  << " are up to date with remote identity provider";
2329  } else {
2330  if (!roles_revoked.empty()) {
2331  LOG(INFO) << "Roles revoked during synchronization with identity provider for user "
2332  << user_name << ": " << join(roles_revoked, " ");
2333  }
2334  if (!roles_granted.empty()) {
2335  LOG(INFO) << "Roles granted during synchronization with identity provider for user "
2336  << user_name << ": " << join(roles_granted, " ");
2337  }
2338  }
2339 }
2340 
2341 std::unordered_map<std::string, std::vector<std::string>>
2342 SysCatalog::getGranteesOfSharedDashboards(const std::vector<std::string>& dashboard_ids) {
2344  std::unordered_map<std::string, std::vector<std::string>> active_grantees;
2345  sqliteConnector_->query("BEGIN TRANSACTION");
2346  try {
2347  for (auto dash : dashboard_ids) {
2348  std::vector<std::string> grantees = {};
2349  sqliteConnector_->query_with_text_params(
2350  "SELECT roleName FROM mapd_object_permissions WHERE objectPermissions NOT IN "
2351  "(0,1) AND objectPermissionsType = ? AND objectId = ?",
2352  std::vector<std::string>{
2353  std::to_string(static_cast<int32_t>(DashboardDBObjectType)), dash});
2354  int num_rows = sqliteConnector_->getNumRows();
2355  if (num_rows == 0) {
2356  // no grantees
2357  continue;
2358  } else {
2359  for (size_t i = 0; i < sqliteConnector_->getNumRows(); ++i) {
2360  grantees.push_back(sqliteConnector_->getData<string>(i, 0));
2361  }
2362  active_grantees[dash] = grantees;
2363  }
2364  }
2365  } catch (const std::exception& e) {
2366  sqliteConnector_->query("ROLLBACK TRANSACTION");
2367  throw;
2368  }
2369  sqliteConnector_->query("END TRANSACTION");
2370  return active_grantees;
2371 }
2372 
2373 } // namespace Catalog_Namespace
static const AccessPrivileges VIEW_SQL_EDITOR
Definition: DBObject.h:153
bool g_enable_fsi
Definition: Catalog.cpp:90
const int8_t const int64_t * num_rows
class for a per-database catalog. also includes metadata for the current database and the current use...
Definition: Catalog.h:86
static const AccessPrivileges ALL_DATABASE
Definition: DBObject.h:152
DBObjectType
Definition: DBObject.h:42
void updatePrivileges(const DBObject &object)
Definition: DBObject.cpp:141
static const AccessPrivileges ALL_TABLE_MIGRATE
Definition: DBObject.h:157
#define LOG(tag)
Definition: Logger.h:188
static const int32_t ALL
Definition: DBObject.h:79
std::string join(T const &container, std::string const &delim)
specifies the object_roles content in-memory of a row in mapd_object_permissions table ...
#define UNREACHABLE()
Definition: Logger.h:241
void setObjectKey(const DBObjectKey &objectKey)
Definition: DBObject.h:215
const std::string OMNISCI_SYSTEM_CATALOG
Definition: SysCatalog.h:57
Definition: Grantee.h:70
int32_t objectId
Definition: DBObject.h:57
void setName(std::string name)
Definition: DBObject.h:208
Definition: Grantee.h:76
void setPrivileges(const AccessPrivileges &privs)
Definition: DBObject.h:217
void insertOrUpdateObjectPrivileges(std::unique_ptr< SqliteConnector > &sqliteConnector, std::string roleName, bool userRole, DBObject &object)
Definition: SysCatalog.cpp:341
std::string to_string(char const *&&v)
static const AccessPrivileges ALL_VIEW
Definition: DBObject.h:178
This file contains the class specification and related data structures for Catalog.
DBObjectKey getObjectKey() const
Definition: DBObject.h:211
static DBObjectKey fromString(const std::vector< std::string > &key, const DBObjectType &type)
Definition: DBObject.cpp:259
This file contains the class specification and related data structures for SysCatalog.
std::string cat(Ts &&... args)
static bool parseUserMetadataFromSQLite(const std::unique_ptr< SqliteConnector > &conn, UserMetadata &user)
void setPermissionType(const DBObjectType &permissionType)
Definition: DBObject.cpp:149
void init(LogOptions const &log_opts)
Definition: Logger.cpp:276
const std::string OMNISCI_DEFAULT_DB
Definition: SysCatalog.h:58
std::string generate_random_string(const size_t len)
virtual void revokeAllOnDatabase(int32_t dbId)
Definition: Grantee.cpp:279
std::string hash_with_bcrypt(const std::string &pwd)
Definition: SysCatalog.cpp:66
static const int32_t MAPD_VERSION
Definition: release.h:33
static const AccessPrivileges ALL_DASHBOARD_MIGRATE
Definition: DBObject.h:169
static const AccessPrivileges ALL_SERVER
Definition: DBObject.h:188
static const AccessPrivileges NONE
Definition: DBObject.h:149
void deleteObjectPrivileges(std::unique_ptr< SqliteConnector > &sqliteConnector, std::string roleName, bool userRole, DBObject &object)
Definition: SysCatalog.cpp:322
const DBMetadata & getCurrentDB() const
Definition: Catalog.h:194
static const std::string SYSTEM_ROLE_TAG("#dash_system_role")
specifies the content in-memory of a row in the dashboard
std::string to_upper(const std::string &str)
void loadKey()
Definition: DBObject.cpp:179
void setObjectType(const DBObjectType &objectType)
Definition: DBObject.cpp:152
const std::string OMNISCI_ROOT_USER
Definition: SysCatalog.h:59
static const AccessPrivileges ALL_VIEW_MIGRATE
Definition: DBObject.h:177
const std::string OMNISCI_ROOT_PASSWD_DEFAULT
Definition: SysCatalog.h:62
const int OMNISCI_ROOT_USER_ID
Definition: SysCatalog.h:60
int32_t dbId
Definition: DBObject.h:56
static const AccessPrivileges ALL_DASHBOARD
Definition: DBObject.h:170
static const AccessPrivileges ACCESS
Definition: DBObject.h:154
static const AccessPrivileges ALL_TABLE
Definition: DBObject.h:158
const std::string OMNISCI_ROOT_USER_ID_STR
Definition: SysCatalog.h:61
mapd_shared_lock< mapd_shared_mutex > read_lock
auto get_users(std::unique_ptr< SqliteConnector > &sqliteConnector, const int32_t dbId=-1)
#define CHECK(condition)
Definition: Logger.h:197
std::list< DBSummary > DBSummaryList
Definition: SysCatalog.h:120
int32_t permissionType
Definition: DBObject.h:55
mapd_unique_lock< mapd_shared_mutex > write_lock
int64_t privileges
Definition: DBObject.h:134
read_lock< SysCatalog > sys_read_lock
Definition: Catalog.cpp:110
virtual void renameDbObject(const DBObject &object)
Definition: Grantee.cpp:108
std::atomic< bool > isSuper
Definition: SysCatalog.h:96