OmniSciDB  cde582ebc3
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Groups Pages
SysCatalog.cpp
Go to the documentation of this file.
1 /*
2  * Copyright 2022 HEAVY.AI, 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 
23 #include "SysCatalog.h"
24 #include <algorithm>
25 #include <cassert>
26 #include <exception>
27 #include <filesystem>
28 #include <list>
29 #include <memory>
30 #include <random>
31 #include <sstream>
32 #include <string_view>
33 #include "Catalog.h"
34 
35 #include "Catalog/AuthMetadata.h"
37 
38 #include <boost/algorithm/string/predicate.hpp>
39 #include <boost/filesystem.hpp>
40 #include <boost/range/adaptor/map.hpp>
41 #include <boost/version.hpp>
42 
43 #include "MapDRelease.h"
44 #include "Parser/ParserNode.h"
45 #include "RWLocks.h"
46 #include "Shared/File.h"
47 #include "Shared/StringTransform.h"
48 #include "Shared/SysDefinitions.h"
49 #include "Shared/measure.h"
50 #include "Shared/misc.h"
51 #include "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 std::string g_base_path;
65 
66 extern bool g_enable_fsi;
67 extern bool g_read_only;
68 
69 namespace {
70 
71 std::string hash_with_bcrypt(const std::string& pwd) {
72  char salt[BCRYPT_HASHSIZE], hash[BCRYPT_HASHSIZE];
73  CHECK(bcrypt_gensalt(-1, salt) == 0);
74  CHECK(bcrypt_hashpw(pwd.c_str(), salt, hash) == 0);
75  return std::string(hash, BCRYPT_HASHSIZE);
76 }
77 
78 // This catalog copy must take place before any other catalog accesses.
79 std::filesystem::path copy_catalog_if_read_only(std::filesystem::path base_data_path) {
80  std::filesystem::path catalog_base_data_path;
81 
82  // For a read-only server, make a temporary copy of the catalog directory.
83  // This catalog copy must take place before any other catalog accesses.
84  if (!g_read_only) {
85  // Catalog directory will be in the normal location.
86  catalog_base_data_path = base_data_path;
87  } else {
88  // Catalog directory will be in a temporary location.
89  catalog_base_data_path = base_data_path / "temporary";
90 
91  // Delete the temporary directory if it exists.
92  // The name "temporary" is hardcoded so nobody should object to its deletion!
93  CHECK_NE(catalog_base_data_path.string().find("temporary"), std::string::npos);
94  CHECK_NE(catalog_base_data_path, base_data_path);
95  if (std::filesystem::exists(catalog_base_data_path)) {
96  std::filesystem::remove_all(catalog_base_data_path);
97  }
98  std::filesystem::create_directories(catalog_base_data_path);
99 
100  // Make the temporary copy of the catalog.
101  const auto normal_catalog_path = base_data_path / shared::kCatalogDirectoryName;
102  const auto temporary_catalog_path =
103  catalog_base_data_path / shared::kCatalogDirectoryName;
104  LOG(INFO) << "copying catalog from " << normal_catalog_path << " to "
105  << temporary_catalog_path << " for read-only server";
106  std::filesystem::copy(normal_catalog_path,
107  temporary_catalog_path,
108  std::filesystem::copy_options::recursive);
109  }
110 
111  return catalog_base_data_path;
112 }
113 
114 } // namespace
115 
116 namespace Catalog_Namespace {
117 
118 thread_local bool SysCatalog::thread_holds_read_lock = false;
119 std::unique_ptr<SysCatalog> SysCatalog::instance_;
120 
121 using sys_read_lock = read_lock<SysCatalog>;
124 
125 bool g_log_user_id{false}; // --log-user-id
126 
127 std::string UserMetadata::userLoggable() const {
128  return g_log_user_id ? std::to_string(userId) : userName;
129 }
130 
131 auto CommonFileOperations::assembleCatalogName(std::string const& name) {
132  return base_path_ + "/" + shared::kCatalogDirectoryName + "/" + name;
133 };
134 
135 void CommonFileOperations::removeCatalogByFullPath(std::string const& full_path) {
136  boost::filesystem::remove(full_path);
137 }
138 
139 void CommonFileOperations::removeCatalogByName(std::string const& name) {
140  boost::filesystem::remove(assembleCatalogName(name));
141 };
142 
143 auto CommonFileOperations::duplicateAndRenameCatalog(std::string const& current_name,
144  std::string const& new_name) {
145  auto full_current_path = assembleCatalogName(current_name);
146  auto full_new_path = assembleCatalogName(new_name);
147 
148  try {
149  boost::filesystem::copy_file(full_current_path, full_new_path);
150  } catch (std::exception& e) {
151  std::string err_message{"Could not copy file " + full_current_path + " to " +
152  full_new_path + " exception was " + e.what()};
153  LOG(ERROR) << err_message;
154  throw std::runtime_error(err_message);
155  }
156 
157  return std::make_pair(full_current_path, full_new_path);
158 };
159 
160 void SysCatalog::init(const std::string& basePath,
161  std::shared_ptr<Data_Namespace::DataMgr> dataMgr,
162  const AuthMetadata& authMetadata,
163  std::shared_ptr<Calcite> calcite,
164  bool is_new_db,
165  bool aggregator,
166  const std::vector<LeafHostInfo>& string_dict_hosts) {
167  basePath_ = !g_multi_instance ? copy_catalog_if_read_only(basePath).string() : basePath;
168  sqliteConnector_.reset(new SqliteConnector(
170  dcatalogMutex_ = std::make_unique<heavyai::DistributedSharedMutex>(
171  std::filesystem::path(basePath_) / shared::kLockfilesDirectoryName /
173  [this](size_t) {
175  *dsqliteMutex_);
176  buildMapsUnlocked();
177  });
178  dsqliteMutex_ = std::make_unique<heavyai::DistributedSharedMutex>(
179  std::filesystem::path(basePath_) / shared::kLockfilesDirectoryName /
183  dataMgr_ = dataMgr;
184  authMetadata_ = &authMetadata;
185  pki_server_.reset(new PkiServer(*authMetadata_));
186  calciteMgr_ = calcite;
187  string_dict_hosts_ = string_dict_hosts;
188  aggregator_ = aggregator;
190  if (is_new_db) {
191  initDB();
192  } else {
193  bool db_exists =
194  boost::filesystem::exists(basePath_ + "/" + shared::kCatalogDirectoryName + "/" +
196  if (!db_exists) {
197  importDataFromOldMapdDB();
198  }
200  checkAndExecuteMigrations();
202  }
203  }
204  buildMaps(is_new_db);
205 }
206 
207 void SysCatalog::buildMaps(bool is_new_db) {
210 
211  buildMapsUnlocked(is_new_db);
212 }
213 
214 void SysCatalog::buildMapsUnlocked(bool is_new_db) {
215  VLOG(2) << "reloading catalog caches for: " << shared::kSystemCatalogName;
216 
217  // Store permissions for temporary users.
218  std::map<std::string, std::vector<std::string>> tu_map;
219  for (auto& pair : temporary_users_by_name_) {
220  CHECK(pair.second);
221  UserMetadata& user = *pair.second;
222  auto it = granteeMap_.find(to_upper(user.userName));
223  CHECK(it != granteeMap_.end()) << to_upper(user.userName) << " not found";
224 
225  auto user_rl = dynamic_cast<User*>(it->second.get());
226  CHECK(user_rl);
227  std::vector<std::string> current_roles = user_rl->getRoles();
228  auto result = tu_map.emplace(user.userName, std::move(current_roles));
229  CHECK(result.second);
230  }
231 
232  // Forget permissions and reload them from file storage.
233  buildRoleMapUnlocked();
234  buildUserRoleMapUnlocked();
235  buildObjectDescriptorMapUnlocked();
236  if (!is_new_db) {
237  // We don't want to create the information schema db during database initialization
238  // because we don't have the appropriate context to intialize the tables. For
239  // instance if the server is intended to run in distributed mode, initializing the
240  // table as part of initdb will be missing information such as the location of the
241  // string dictionary server.
242  initializeInformationSchemaDb();
243  }
244 
245  // Restore permissions for temporary users that were stored above.
246  for (auto& pair : temporary_users_by_name_) {
247  CHECK(pair.second);
248  UserMetadata& user = *pair.second;
249 
250  createRole_unsafe(user.userName, /*user_private_role*/ true, /*is_temporary*/ true);
251 
252  auto it = tu_map.find(user.userName);
253  CHECK(it != tu_map.end()) << user.userName << " not found";
254  for (const auto& r : it->second) {
255  grantRole_unsafe(r, user.userName, /*is_temporary*/ true);
256  }
257  }
258 }
259 
260 SysCatalog::SysCatalog()
262  , aggregator_{false}
263  , sqliteMutex_{}
264  , sharedMutex_{}
265  , thread_holding_sqlite_lock{std::thread::id()}
266  , thread_holding_write_lock{std::thread::id()} {}
267 
269  // TODO(sy): Need to lock here to wait for other threads to complete before pulling out
270  // the rug from under them. Unfortunately this lock was seen to deadlock because the
271  // HeavyDB shutdown sequence needs cleanup. Do we even need these clear()'s anymore?
272  // sys_write_lock write_lock(this);
273  granteeMap_.clear();
274  objectDescriptorMap_.clear();
275  cat_map_.clear();
276 }
277 
279  if (g_read_only) {
280  throw std::runtime_error("can't init a new database in read-only mode");
281  }
283  sqliteConnector_->query("BEGIN TRANSACTION");
284  try {
285  sqliteConnector_->query(
286  "CREATE TABLE mapd_users (userid integer primary key, name text unique, "
287  "passwd_hash text, issuper boolean, default_db integer references "
288  "mapd_databases, can_login boolean)");
289  sqliteConnector_->query_with_text_params(
290  "INSERT INTO mapd_users VALUES (?, ?, ?, 1, NULL, 1)",
291  std::vector<std::string>{shared::kRootUserIdStr,
294  sqliteConnector_->query(
295  "CREATE TABLE mapd_databases (dbid integer primary key, name text unique, owner "
296  "integer references mapd_users)");
297  sqliteConnector_->query(
298  "CREATE TABLE mapd_roles(roleName text, userName text, UNIQUE(roleName, "
299  "userName))");
300  sqliteConnector_->query(
301  "CREATE TABLE mapd_object_permissions ("
302  "roleName text, "
303  "roleType bool, "
304  "dbId integer references mapd_databases, "
305  "objectName text, "
306  "objectId integer, "
307  "objectPermissionsType integer, "
308  "objectPermissions integer, "
309  "objectOwnerId integer, UNIQUE(roleName, objectPermissionsType, dbId, "
310  "objectId))");
311  } catch (const std::exception&) {
312  sqliteConnector_->query("ROLLBACK TRANSACTION");
313  throw;
314  }
315  sqliteConnector_->query("END TRANSACTION");
318  shared::kRootUsername, /*userPrivateRole=*/true, /*is_temporary=*/false);
319 }
320 
323  createRoles();
327  updateUserSchema(); // must come before updatePasswordsToHashes()
329  updateBlankPasswordsToRandom(); // must come after updatePasswordsToHashes()
332 }
333 
336 
337  // check to see if the new column already exists
338  sqliteConnector_->query("PRAGMA TABLE_INFO(mapd_users)");
339  for (size_t i = 0; i < sqliteConnector_->getNumRows(); i++) {
340  const auto& col_name = sqliteConnector_->getData<std::string>(i, 1);
341  if (col_name == "default_db") {
342  return; // new column already exists
343  }
344  }
345 
346  // create the new column
347  sqliteConnector_->query("BEGIN TRANSACTION");
348  try {
349  sqliteConnector_->query(
350  "ALTER TABLE mapd_users ADD COLUMN default_db INTEGER REFERENCES mapd_databases");
351  } catch (const std::exception& e) {
352  sqliteConnector_->query("ROLLBACK TRANSACTION");
353  throw;
354  }
355  sqliteConnector_->query("END TRANSACTION");
356 }
357 
360  std::string mapd_db_path = basePath_ + "/" + shared::kCatalogDirectoryName + "/mapd";
361  sqliteConnector_->query("ATTACH DATABASE `" + mapd_db_path + "` as old_cat");
362  sqliteConnector_->query("BEGIN TRANSACTION");
363  LOG(INFO) << "Moving global metadata into a separate catalog";
364  try {
365  auto moveTableIfExists = [conn = sqliteConnector_.get()](const std::string& tableName,
366  bool deleteOld = true) {
367  conn->query("SELECT sql FROM old_cat.sqlite_master WHERE type='table' AND name='" +
368  tableName + "'");
369  if (conn->getNumRows() != 0) {
370  conn->query(conn->getData<string>(0, 0));
371  conn->query("INSERT INTO " + tableName + " SELECT * FROM old_cat." + tableName);
372  if (deleteOld) {
373  conn->query("DROP TABLE old_cat." + tableName);
374  }
375  }
376  };
377  moveTableIfExists("mapd_users");
378  moveTableIfExists("mapd_databases");
379  moveTableIfExists("mapd_roles");
380  moveTableIfExists("mapd_object_permissions");
381  moveTableIfExists("mapd_privileges");
382  moveTableIfExists("mapd_version_history", false);
383  } catch (const std::exception& e) {
384  LOG(ERROR) << "Failed to move global metadata into a separate catalog: " << e.what();
385  sqliteConnector_->query("ROLLBACK TRANSACTION");
386  try {
387  sqliteConnector_->query("DETACH DATABASE old_cat");
388  } catch (const std::exception&) {
389  // nothing to do here
390  }
391  throw;
392  }
393  sqliteConnector_->query("END TRANSACTION");
394  const std::string sys_catalog_path =
395  basePath_ + "/" + shared::kCatalogDirectoryName + "/" + shared::kSystemCatalogName;
396  LOG(INFO) << "Global metadata has been successfully moved into a separate catalog: "
397  << sys_catalog_path
398  << ". Using this database with an older version of heavydb "
399  "is now impossible.";
400  try {
401  sqliteConnector_->query("DETACH DATABASE old_cat");
402  } catch (const std::exception&) {
403  // nothing to do here
404  }
405 }
406 
409  sqliteConnector_->query("BEGIN TRANSACTION");
410  try {
411  sqliteConnector_->query(
412  "SELECT name FROM sqlite_master WHERE type='table' AND name='mapd_roles'");
413  if (sqliteConnector_->getNumRows() != 0) {
414  // already done
415  sqliteConnector_->query("END TRANSACTION");
416  return;
417  }
418  sqliteConnector_->query(
419  "CREATE TABLE mapd_roles(roleName text, userName text, UNIQUE(roleName, "
420  "userName))");
421  } catch (const std::exception&) {
422  sqliteConnector_->query("ROLLBACK TRANSACTION");
423  throw;
424  }
425  sqliteConnector_->query("END TRANSACTION");
426 }
427 
428 /*
429  There was an error in how we migrated users from pre-4.0 versions where we would copy
430  all user names into the mapd_roles table. This table should never have usernames in it
431  (the correct migration was to copy users into the mapd_object_permissions table instead)
432  so this migration function prunes such cases out.
433  */
436  sqliteConnector_->query("BEGIN TRANSACTION");
437  try {
438  sqliteConnector_->query("SELECT name FROM mapd_users");
439  auto num_rows = sqliteConnector_->getNumRows();
440  std::vector<std::string> user_names;
441  for (size_t i = 0; i < num_rows; ++i) {
442  user_names.push_back(sqliteConnector_->getData<std::string>(i, 0));
443  }
444  for (const auto& user_name : user_names) {
445  sqliteConnector_->query_with_text_param("DELETE FROM mapd_roles WHERE roleName = ?",
446  user_name);
447  }
448  } catch (const std::exception&) {
449  sqliteConnector_->query("ROLLBACK TRANSACTION");
450  throw;
451  }
452  sqliteConnector_->query("END TRANSACTION");
453 }
454 
455 namespace {
456 
457 void deleteObjectPrivileges(std::unique_ptr<SqliteConnector>& sqliteConnector,
458  std::string roleName,
459  bool userRole,
460  DBObject& object) {
461  DBObjectKey key = object.getObjectKey();
462 
463  sqliteConnector->query_with_text_params(
464  "DELETE FROM mapd_object_permissions WHERE roleName = ?1 and roleType = ?2 and "
465  "objectPermissionsType = ?3 and "
466  "dbId = "
467  "?4 "
468  "and objectId = ?5",
469  std::vector<std::string>{roleName,
470  std::to_string(userRole),
472  std::to_string(key.dbId),
473  std::to_string(key.objectId)});
474 }
475 
476 void insertOrUpdateObjectPrivileges(std::unique_ptr<SqliteConnector>& sqliteConnector,
477  std::string roleName,
478  bool userRole,
479  const DBObject& object) {
480  CHECK(object.valid());
481  DBObjectKey key = object.getObjectKey();
482 
483  sqliteConnector->query_with_text_params(
484  "INSERT OR REPLACE INTO mapd_object_permissions("
485  "roleName, "
486  "roleType, "
487  "objectPermissionsType, "
488  "dbId, "
489  "objectId, "
490  "objectPermissions, "
491  "objectOwnerId,"
492  "objectName) "
493  "VALUES (?1, ?2, ?3, "
494  "?4, ?5, ?6, ?7, ?8)",
495  std::vector<std::string>{
496  roleName, // roleName
497  userRole ? "1" : "0", // roleType
498  std::to_string(key.permissionType), // permissionType
499  std::to_string(key.dbId), // dbId
500  std::to_string(key.objectId), // objectId
501  std::to_string(object.getPrivileges().privileges), // objectPrivileges
502  std::to_string(object.getOwner()), // objectOwnerId
503  object.getName() // name
504  });
505 }
506 
507 } // namespace
508 
511  sqliteConnector_->query("BEGIN TRANSACTION");
512  try {
513  sqliteConnector_->query(
514  "SELECT name FROM sqlite_master WHERE type='table' AND "
515  "name='mapd_object_permissions'");
516  if (sqliteConnector_->getNumRows() != 0) {
517  // already done
518  sqliteConnector_->query("END TRANSACTION");
519  return;
520  }
521 
522  sqliteConnector_->query(
523  "CREATE TABLE IF NOT EXISTS mapd_object_permissions ("
524  "roleName text, "
525  "roleType bool, "
526  "dbId integer references mapd_databases, "
527  "objectName text, "
528  "objectId integer, "
529  "objectPermissionsType integer, "
530  "objectPermissions integer, "
531  "objectOwnerId integer, UNIQUE(roleName, objectPermissionsType, dbId, "
532  "objectId))");
533 
534  // get the list of databases and their grantees
535  sqliteConnector_->query(
536  "SELECT userid, dbid FROM mapd_privileges WHERE select_priv = 1 and insert_priv "
537  "= 1");
538  size_t numRows = sqliteConnector_->getNumRows();
539  vector<pair<int, int>> db_grantees(numRows);
540  for (size_t i = 0; i < numRows; ++i) {
541  db_grantees[i].first = sqliteConnector_->getData<int>(i, 0);
542  db_grantees[i].second = sqliteConnector_->getData<int>(i, 1);
543  }
544  // map user names to user ids
545  sqliteConnector_->query("select userid, name from mapd_users");
546  numRows = sqliteConnector_->getNumRows();
547  std::unordered_map<int, string> users_by_id;
548  std::unordered_map<int, bool> user_has_privs;
549  for (size_t i = 0; i < numRows; ++i) {
550  users_by_id[sqliteConnector_->getData<int>(i, 0)] =
551  sqliteConnector_->getData<string>(i, 1);
552  user_has_privs[sqliteConnector_->getData<int>(i, 0)] = false;
553  }
554  // map db names to db ids
555  sqliteConnector_->query("select dbid, name from mapd_databases");
556  numRows = sqliteConnector_->getNumRows();
557  std::unordered_map<int, string> dbs_by_id;
558  for (size_t i = 0; i < numRows; ++i) {
559  dbs_by_id[sqliteConnector_->getData<int>(i, 0)] =
560  sqliteConnector_->getData<string>(i, 1);
561  }
562  // migrate old privileges to new privileges: if user had insert access to database, he
563  // was a grantee
564  for (const auto& grantee : db_grantees) {
565  user_has_privs[grantee.first] = true;
566  auto dbName = dbs_by_id[grantee.second];
567  {
568  // table level permissions
570  DBObjectKey key{type, grantee.second};
571  DBObject object(
574  sqliteConnector_, users_by_id[grantee.first], true, object);
575  }
576 
577  {
578  // dashboard level permissions
580  DBObjectKey key{type, grantee.second};
581  DBObject object(dbName,
582  type,
583  key,
587  sqliteConnector_, users_by_id[grantee.first], true, object);
588  }
589 
590  {
591  // view level permissions
593  DBObjectKey key{type, grantee.second};
594  DBObject object(
597  sqliteConnector_, users_by_id[grantee.first], true, object);
598  }
599  }
600  for (auto user : user_has_privs) {
601  auto dbName = dbs_by_id[0];
602  if (user.second == false && user.first != shared::kRootUserId) {
603  {
605  DBObjectKey key{type, 0};
608  sqliteConnector_, users_by_id[user.first], true, object);
609  }
610  }
611  }
612  } catch (const std::exception&) {
613  sqliteConnector_->query("ROLLBACK TRANSACTION");
614  throw;
615  }
616  sqliteConnector_->query("END TRANSACTION");
617 }
618 
621  sqliteConnector_->query("BEGIN TRANSACTION");
622  try {
623  sqliteConnector_->query(
624  "SELECT roleName FROM mapd_object_permissions WHERE roleName = \'" +
625  shared::kRootUsername + "\'");
626  if (sqliteConnector_->getNumRows() != 0) {
627  // already done
628  sqliteConnector_->query("END TRANSACTION");
629  return;
630  }
631 
633  shared::kRootUsername, /*userPrivateRole=*/true, /*is_temporary=*/false);
634  } catch (const std::exception&) {
635  sqliteConnector_->query("ROLLBACK TRANSACTION");
636  throw;
637  }
638  sqliteConnector_->query("END TRANSACTION");
639 }
640 
643  sqliteConnector_->query("BEGIN TRANSACTION");
644  try {
645  sqliteConnector_->query(
646  "SELECT name FROM sqlite_master WHERE type='table' AND name='mapd_users'");
647  if (sqliteConnector_->getNumRows() == 0) {
648  // Nothing to update
649  sqliteConnector_->query("END TRANSACTION");
650  return;
651  }
652  sqliteConnector_->query("PRAGMA TABLE_INFO(mapd_users)");
653  for (size_t i = 0; i < sqliteConnector_->getNumRows(); i++) {
654  const auto& col_name = sqliteConnector_->getData<std::string>(i, 1);
655  if (col_name == "passwd_hash") {
656  sqliteConnector_->query("END TRANSACTION");
657  return;
658  }
659  }
660  // Alas, SQLite can't drop columns so we have to recreate the table
661  // (or, optionally, add the new column and reset the old one to a bunch of nulls)
662  sqliteConnector_->query("SELECT userid, passwd FROM mapd_users");
663  auto numRows = sqliteConnector_->getNumRows();
664  vector<std::string> users, passwords;
665  for (size_t i = 0; i < numRows; i++) {
666  users.push_back(sqliteConnector_->getData<std::string>(i, 0));
667  passwords.push_back(sqliteConnector_->getData<std::string>(i, 1));
668  }
669  sqliteConnector_->query(
670  "CREATE TABLE mapd_users_tmp (userid integer primary key, name text unique, "
671  "passwd_hash text, issuper boolean, default_db integer references "
672  "mapd_databases)");
673  sqliteConnector_->query(
674  "INSERT INTO mapd_users_tmp(userid, name, passwd_hash, issuper, default_db) "
675  "SELECT userid, name, null, issuper, default_db FROM mapd_users");
676  for (size_t i = 0; i < users.size(); ++i) {
677  sqliteConnector_->query_with_text_params(
678  "UPDATE mapd_users_tmp SET passwd_hash = ? WHERE userid = ?",
679  std::vector<std::string>{hash_with_bcrypt(passwords[i]), users[i]});
680  }
681  sqliteConnector_->query("DROP TABLE mapd_users");
682  sqliteConnector_->query("ALTER TABLE mapd_users_tmp RENAME TO mapd_users");
683  } catch (const std::exception& e) {
684  LOG(ERROR) << "Failed to hash passwords: " << e.what();
685  sqliteConnector_->query("ROLLBACK TRANSACTION");
686  throw;
687  }
688  sqliteConnector_->query("END TRANSACTION");
689  sqliteConnector_->query("VACUUM"); // physically delete plain text passwords
690  LOG(INFO) << "Passwords were successfully hashed";
691 }
692 
694  const std::string UPDATE_BLANK_PASSWORDS_TO_RANDOM = "update_blank_passwords_to_random";
695  sqliteConnector_->query_with_text_params(
696  "SELECT migration_history FROM mapd_version_history WHERE migration_history = ?",
697  std::vector<std::string>{UPDATE_BLANK_PASSWORDS_TO_RANDOM});
698  if (sqliteConnector_->getNumRows()) {
699  return;
700  }
701 
703  sqliteConnector_->query("BEGIN TRANSACTION");
704  try {
705  sqliteConnector_->query(
706  "SELECT userid, passwd_hash, name FROM mapd_users WHERE name <> 'mapd'");
707  auto numRows = sqliteConnector_->getNumRows();
708  vector<std::string> users, passwords, names;
709  for (size_t i = 0; i < numRows; i++) {
710  users.push_back(sqliteConnector_->getData<std::string>(i, 0));
711  passwords.push_back(sqliteConnector_->getData<std::string>(i, 1));
712  names.push_back(sqliteConnector_->getData<std::string>(i, 2));
713  }
714  for (size_t i = 0; i < users.size(); ++i) {
715  int pwd_check_result = bcrypt_checkpw("", passwords[i].c_str());
716  // if the check fails there is a good chance that data on disc is broken
717  CHECK(pwd_check_result >= 0);
718  if (pwd_check_result != 0) {
719  continue;
720  }
721  LOG(WARNING) << "resetting blank password for user " << names[i] << " (" << users[i]
722  << ") to a random password";
723  sqliteConnector_->query_with_text_params(
724  "UPDATE mapd_users SET passwd_hash = ? WHERE userid = ?",
725  std::vector<std::string>{hash_with_bcrypt(generate_random_string(72)),
726  users[i]});
727  }
728  sqliteConnector_->query_with_text_params(
729  "INSERT INTO mapd_version_history(version, migration_history) values(?,?)",
730  std::vector<std::string>{std::to_string(MAPD_VERSION),
731  UPDATE_BLANK_PASSWORDS_TO_RANDOM});
732  } catch (const std::exception& e) {
733  LOG(ERROR) << "Failed to fix blank passwords: " << e.what();
734  sqliteConnector_->query("ROLLBACK TRANSACTION");
735  throw;
736  }
737  sqliteConnector_->query("END TRANSACTION");
738 }
739 
741  const std::string UPDATE_SUPPORT_USER_DEACTIVATION = "update_support_user_deactivation";
743  // check to see if the new column already exists
744  sqliteConnector_->query("PRAGMA TABLE_INFO(mapd_users)");
745  for (size_t i = 0; i < sqliteConnector_->getNumRows(); i++) {
746  const auto& col_name = sqliteConnector_->getData<std::string>(i, 1);
747  if (col_name == "can_login") {
748  return; // new column already exists
749  }
750  }
751  sqliteConnector_->query("BEGIN TRANSACTION");
752  try {
753  sqliteConnector_->query("ALTER TABLE mapd_users ADD COLUMN can_login BOOLEAN");
754  sqliteConnector_->query("UPDATE mapd_users SET can_login = true");
755  sqliteConnector_->query_with_text_params(
756  "INSERT INTO mapd_version_history(version, migration_history) values(?,?)",
757  std::vector<std::string>{std::to_string(MAPD_VERSION),
758  UPDATE_SUPPORT_USER_DEACTIVATION});
759  } catch (const std::exception& e) {
760  LOG(ERROR) << "Failed to add support for user deactivation: " << e.what();
761  sqliteConnector_->query("ROLLBACK TRANSACTION");
762  throw;
763  }
764  sqliteConnector_->query("END TRANSACTION");
765 }
766 
769  sqliteConnector_->query("BEGIN TRANSACTION");
770  try {
771  sqliteConnector_->query(
772  "select name from sqlite_master WHERE type='table' AND "
773  "name='mapd_version_history'");
774  if (sqliteConnector_->getNumRows() == 0) {
775  sqliteConnector_->query(
776  "CREATE TABLE mapd_version_history(version integer, migration_history text "
777  "unique)");
778  } else {
779  sqliteConnector_->query(
780  "select * from mapd_version_history where migration_history = "
781  "'db_access_privileges'");
782  if (sqliteConnector_->getNumRows() != 0) {
783  // both privileges migrated
784  // no need for further execution
785  sqliteConnector_->query("END TRANSACTION");
786  return;
787  }
788  }
789  // Insert check for migration
790  sqliteConnector_->query_with_text_params(
791  "INSERT INTO mapd_version_history(version, migration_history) values(?,?)",
792  std::vector<std::string>{std::to_string(MAPD_VERSION), "db_access_privileges"});
793 
794  sqliteConnector_->query("select dbid, name from mapd_databases");
795  std::unordered_map<int, string> databases;
796  for (size_t i = 0; i < sqliteConnector_->getNumRows(); ++i) {
797  databases[sqliteConnector_->getData<int>(i, 0)] =
798  sqliteConnector_->getData<string>(i, 1);
799  }
800 
801  sqliteConnector_->query("select userid, name from mapd_users");
802  std::unordered_map<int, string> users;
803  for (size_t i = 0; i < sqliteConnector_->getNumRows(); ++i) {
804  users[sqliteConnector_->getData<int>(i, 0)] =
805  sqliteConnector_->getData<string>(i, 1);
806  }
807 
808  // All existing users by default will be granted DB Access permissions
809  // and view sql editor privileges
810  DBMetadata dbmeta;
811  for (auto db_ : databases) {
812  CHECK(getMetadataForDB(db_.second, dbmeta));
813  for (auto user : users) {
814  if (user.first != shared::kRootUserId) {
815  {
816  DBObjectKey key;
818  key.dbId = dbmeta.dbId;
819 
820  // access permission;
821  DBObject object_access(key, AccessPrivileges::ACCESS, dbmeta.dbOwner);
823  object_access.setName(dbmeta.dbName);
824  // sql_editor permission
825  DBObject object_editor(
828  object_editor.setName(dbmeta.dbName);
829  object_editor.updatePrivileges(object_access);
831  sqliteConnector_, user.second, true, object_editor);
832  }
833  }
834  }
835  }
836  } catch (const std::exception& e) {
837  LOG(ERROR) << "Failed to migrate db access privileges: " << e.what();
838  sqliteConnector_->query("ROLLBACK TRANSACTION");
839  throw;
840  }
841  sqliteConnector_->query("END TRANSACTION");
842  LOG(INFO) << "Successfully migrated db access privileges";
843 }
844 
847 
848  sqliteConnector_->query("BEGIN TRANSACTION");
849  try {
850  sqliteConnector_->query(
851  "CREATE TABLE IF NOT EXISTS mapd_privileges (userid integer references "
852  "mapd_users, dbid integer references "
853  "mapd_databases, select_priv boolean, insert_priv boolean, UNIQUE(userid, "
854  "dbid))");
855  } catch (const std::exception& e) {
856  sqliteConnector_->query("ROLLBACK TRANSACTION");
857  throw;
858  }
859  sqliteConnector_->query("END TRANSACTION");
860 }
861 
862 std::shared_ptr<Catalog> SysCatalog::login(std::string& dbname,
863  std::string& username,
864  const std::string& password,
865  UserMetadata& user_meta,
866  bool check_password) {
867  // NOTE(sy): The dbname isn't const because getMetadataWithDefaultDB()
868  // can reset it. The username isn't const because SamlServer's
869  // login()/authenticate_user() can reset it.
870 
871  if (check_password) {
872  loginImpl(username, password, user_meta);
873  } else { // not checking for password so user must exist
874  if (!getMetadataForUser(username, user_meta)) {
875  throw std::runtime_error("Invalid credentials.");
876  }
877  }
878  // we should have a user and user_meta by now
879  if (!user_meta.can_login) {
880  throw std::runtime_error("Unauthorized Access: User " + username + " is deactivated");
881  }
883  getMetadataWithDefaultDB(dbname, username, db_meta, user_meta);
884  return getCatalog(db_meta, false);
885 }
886 
887 // loginImpl() with no EE code and no SAML code
888 void SysCatalog::loginImpl(std::string& username,
889  const std::string& password,
890  UserMetadata& user_meta) {
891  if (!checkPasswordForUser(password, username, user_meta)) {
892  throw std::runtime_error("Authentication failure");
893  }
894 }
895 
896 std::shared_ptr<Catalog> SysCatalog::switchDatabase(std::string& dbname,
897  const std::string& username) {
898  DBMetadata db_meta;
899  UserMetadata user_meta;
900 
901  getMetadataWithDefaultDB(dbname, username, db_meta, user_meta);
902 
903  // NOTE(max): register database in Catalog that early to allow ldap
904  // and saml create default user and role privileges on databases
905  auto cat = getCatalog(db_meta, false);
906 
907  DBObject dbObject(dbname, DatabaseDBObjectType);
908  dbObject.loadKey();
910  if (!checkPrivileges(user_meta, std::vector<DBObject>{dbObject})) {
911  throw std::runtime_error("Unauthorized Access: user " + user_meta.userLoggable() +
912  " is not allowed to access database " + dbname + ".");
913  }
914 
915  return cat;
916 }
917 
918 void SysCatalog::check_for_session_encryption(const std::string& pki_cert,
919  std::string& session) {
920  if (!pki_server_->inUse()) {
921  return;
922  }
923  pki_server_->encrypt_session(pki_cert, session);
924 }
925 
927  UserAlterations alts,
928  bool is_temporary) {
931 
932  if (!alts.passwd) {
933  alts.passwd = "";
934  }
935  if (!alts.is_super) {
936  alts.is_super = false;
937  }
938  if (!alts.default_db) {
939  alts.default_db = "";
940  }
941  if (!alts.can_login) {
942  alts.can_login = true;
943  }
944 
945  UserMetadata user;
946  if (getMetadataForUser(name, user)) {
947  throw runtime_error("User " + user.userLoggable() + " already exists.");
948  }
949  if (getGrantee(name)) {
950  std::string const loggable = g_log_user_id ? std::string("") : name + ' ';
951  throw runtime_error(
952  "User " + loggable +
953  "is same as one of existing grantees. User and role names should be unique.");
954  }
955  DBMetadata db;
956  if (!alts.default_db->empty()) {
957  if (!getMetadataForDB(*alts.default_db, db)) {
958  throw runtime_error("DEFAULT_DB " + *alts.default_db + " not found.");
959  }
960  }
961 
962  // Temporary user.
963  if (is_temporary) {
964  if (!g_read_only) {
965  throw std::runtime_error("Temporary users require read-only mode.");
966  // NOTE(sy): We can remove this restriction when we're confident that
967  // nothing permanent can depend on a temporary user.
968  }
969  auto user2 = std::make_shared<UserMetadata>(next_temporary_user_id_++,
970  name,
971  hash_with_bcrypt(*alts.passwd),
972  *alts.is_super,
973  !alts.default_db->empty() ? db.dbId : -1,
974  *alts.can_login,
975  true);
977  temporary_users_by_id_[user2->userId] = user2;
978  createRole_unsafe(name, /*userPrivateRole=*/true, /*is_temporary=*/true);
979  VLOG(1) << "Created temporary user: " << user2->userLoggable();
980  return *user2;
981  }
982 
983  // Normal user.
984  sqliteConnector_->query("BEGIN TRANSACTION");
985  try {
986  std::vector<std::string> vals;
987  if (!alts.default_db->empty()) {
988  vals = {name,
989  hash_with_bcrypt(*alts.passwd),
990  std::to_string(*alts.is_super),
991  std::to_string(db.dbId),
992  std::to_string(*alts.can_login)};
993  sqliteConnector_->query_with_text_params(
994  "INSERT INTO mapd_users (name, passwd_hash, issuper, default_db, can_login) "
995  "VALUES (?, ?, ?, ?, ?)",
996  vals);
997  } else {
998  vals = {name,
999  hash_with_bcrypt(*alts.passwd),
1000  std::to_string(*alts.is_super),
1001  std::to_string(*alts.can_login)};
1002  sqliteConnector_->query_with_text_params(
1003  "INSERT INTO mapd_users (name, passwd_hash, issuper, can_login) "
1004  "VALUES (?, ?, ?, ?)",
1005  vals);
1006  }
1007  createRole_unsafe(name, /*userPrivateRole=*/true, /*is_temporary=*/false);
1008  } catch (const std::exception& e) {
1009  sqliteConnector_->query("ROLLBACK TRANSACTION");
1010  throw;
1011  }
1012  sqliteConnector_->query("END TRANSACTION");
1013  auto u = getUser(name);
1014  CHECK(u);
1015  VLOG(1) << "Created user: " << u->userLoggable();
1016  return *u;
1017 }
1018 
1019 void SysCatalog::dropUser(const string& name) {
1020  sys_write_lock write_lock(this);
1022 
1023  UserMetadata user;
1024  if (!getMetadataForUser(name, user)) {
1025  std::string const loggable = g_log_user_id ? std::string("") : name + ' ';
1026  throw runtime_error("Cannot drop user. User " + loggable + "does not exist.");
1027  }
1028 
1029  // Temporary user.
1030  if (user.is_temporary) {
1031  auto it1 = temporary_users_by_name_.find(name);
1032  CHECK(it1 != temporary_users_by_name_.end());
1033  auto it2 = temporary_users_by_id_.find(it1->second->userId);
1034  CHECK(it2 != temporary_users_by_id_.end());
1035  dropRole_unsafe(name, /*is_temporary=*/true);
1037  temporary_users_by_name_.erase(it1);
1038  temporary_users_by_id_.erase(it2);
1039  return;
1040  }
1041 
1042  // Normal user.
1043 
1044  sqliteConnector_->query("BEGIN TRANSACTION");
1045  try {
1046  dropRole_unsafe(name, /*is_temporary=*/false);
1048  const std::string& roleName(name);
1049  sqliteConnector_->query_with_text_param("DELETE FROM mapd_roles WHERE userName = ?",
1050  roleName);
1051  sqliteConnector_->query("DELETE FROM mapd_users WHERE userid = " +
1052  std::to_string(user.userId));
1053  sqliteConnector_->query("DELETE FROM mapd_privileges WHERE userid = " +
1054  std::to_string(user.userId));
1055  } catch (const std::exception& e) {
1056  sqliteConnector_->query("ROLLBACK TRANSACTION");
1057  throw;
1058  }
1059  sqliteConnector_->query("END TRANSACTION");
1060 }
1061 
1062 std::vector<Catalog*> SysCatalog::getCatalogsForAllDbs() {
1063  std::vector<Catalog*> catalogs{};
1064  const auto& db_metadata_list = getAllDBMetadata();
1065  for (const auto& db_metadata : db_metadata_list) {
1066  catalogs.emplace_back(getCatalog(db_metadata, false).get());
1067  }
1068  return catalogs;
1069 }
1070 
1071 namespace { // anonymous namespace
1072 
1073 auto append_with_commas = [](string& s, const string& t) {
1074  if (!s.empty()) {
1075  s += ", ";
1076  }
1077  s += t;
1078 };
1079 
1080 } // anonymous namespace
1081 
1083  if (passwd && hash_with_bcrypt(*passwd) != user.passwd_hash) {
1084  return true;
1085  }
1086  if (is_super && *is_super != user.isSuper) {
1087  return true;
1088  }
1089  if (default_db) {
1090  DBMetadata db;
1091  if (!default_db->empty()) {
1093  throw std::runtime_error(string("DEFAULT_DB ") + *default_db + " not found.");
1094  }
1095  } else {
1096  db.dbId = -1;
1097  }
1098  if (db.dbId != user.defaultDbId) {
1099  return true;
1100  }
1101  }
1102  if (can_login && *can_login != user.can_login) {
1103  return true;
1104  }
1105  return false;
1106 }
1107 
1108 std::string UserAlterations::toString(bool hide_password) const {
1109  std::stringstream ss;
1110  if (passwd) {
1111  if (hide_password) {
1112  ss << "PASSWORD='XXXXXXXX'";
1113  } else {
1114  ss << "PASSWORD='" << *passwd << "'";
1115  }
1116  }
1117  if (is_super) {
1118  if (!ss.str().empty()) {
1119  ss << ", ";
1120  }
1121  ss << "IS_SUPER='" << (*is_super ? "TRUE" : "FALSE") << "'";
1122  }
1123  if (default_db) {
1124  if (!ss.str().empty()) {
1125  ss << ", ";
1126  }
1127  ss << "DEFAULT_DB='" << *default_db << "'";
1128  }
1129  if (can_login) {
1130  if (!ss.str().empty()) {
1131  ss << ", ";
1132  }
1133  ss << "CAN_LOGIN='" << *can_login << "'";
1134  }
1135  return ss.str();
1136 }
1137 
1139  sys_write_lock write_lock(this);
1141 
1142  UserMetadata user;
1143  if (!getMetadataForUser(name, user)) {
1144  std::string const loggable = g_log_user_id ? std::string("") : name + ' ';
1145  throw runtime_error("Cannot alter user. User " + loggable + "does not exist.");
1146  }
1147  if (!alts.wouldChange(user)) {
1148  return user;
1149  }
1150 
1151  // Temporary user.
1152  if (user.is_temporary) {
1153  if (alts.passwd) {
1154  user.passwd_hash = hash_with_bcrypt(*alts.passwd);
1155  }
1156  if (alts.is_super) {
1157  user.isSuper = *alts.is_super;
1158  }
1159  if (alts.default_db) {
1160  if (!alts.default_db->empty()) {
1161  DBMetadata db;
1162  if (!getMetadataForDB(*alts.default_db, db)) {
1163  throw runtime_error(string("DEFAULT_DB ") + *alts.default_db + " not found.");
1164  }
1165  user.defaultDbId = db.dbId;
1166  } else {
1167  user.defaultDbId = -1;
1168  }
1169  }
1170  if (alts.can_login) {
1171  user.can_login = *alts.can_login;
1172  }
1173  *temporary_users_by_name_[name] = user;
1174  return user;
1175  }
1176 
1177  // Normal user.
1178  sqliteConnector_->query("BEGIN TRANSACTION");
1179  try {
1180  string sql;
1181  std::vector<std::string> values;
1182  if (alts.passwd) {
1183  append_with_commas(sql, "passwd_hash = ?");
1184  values.push_back(hash_with_bcrypt(*alts.passwd));
1185  }
1186  if (alts.is_super) {
1187  append_with_commas(sql, "issuper = ?");
1188  values.push_back(std::to_string(*alts.is_super));
1189  }
1190  if (alts.default_db) {
1191  if (!alts.default_db->empty()) {
1192  append_with_commas(sql, "default_db = ?");
1193  DBMetadata db;
1194  if (!getMetadataForDB(*alts.default_db, db)) {
1195  throw runtime_error(string("DEFAULT_DB ") + *alts.default_db + " not found.");
1196  }
1197  values.push_back(std::to_string(db.dbId));
1198  } else {
1199  append_with_commas(sql, "default_db = NULL");
1200  }
1201  }
1202  if (alts.can_login) {
1203  append_with_commas(sql, "can_login = ?");
1204  values.push_back(std::to_string(*alts.can_login));
1205  }
1206 
1207  sql = "UPDATE mapd_users SET " + sql + " WHERE userid = ?";
1208  values.push_back(std::to_string(user.userId));
1209 
1210  sqliteConnector_->query_with_text_params(sql, values);
1211  } catch (const std::exception& e) {
1212  sqliteConnector_->query("ROLLBACK TRANSACTION");
1213  throw;
1214  }
1215  sqliteConnector_->query("END TRANSACTION");
1216  auto u = getUser(name);
1217  CHECK(u);
1218  VLOG(1) << "Altered user: " << u->userLoggable();
1219  return *u;
1220 }
1221 
1223  return
1224  [](auto& db_connector, auto on_success, auto on_failure, auto&&... query_requests) {
1225  auto query_runner = [&db_connector](auto&&... query_reqs) {
1226  [[gnu::unused]] int throw_away[] = {
1227  (db_connector->query_with_text_params(
1228  std::forward<decltype(query_reqs)>(query_reqs)),
1229  0)...};
1230  };
1231 
1232  db_connector->query("BEGIN TRANSACTION");
1233  try {
1234  query_runner(std::forward<decltype(query_requests)>(query_requests)...);
1235  on_success();
1236  } catch (std::exception&) {
1237  db_connector->query("ROLLBACK TRANSACTION");
1238  on_failure();
1239  throw;
1240  }
1241  db_connector->query("END TRANSACTION");
1242  };
1243 }
1244 
1245 void SysCatalog::updateUserRoleName(const std::string& roleName,
1246  const std::string& newName) {
1247  sys_write_lock write_lock(this);
1248 
1249  auto it = granteeMap_.find(to_upper(roleName));
1250  if (it != granteeMap_.end()) {
1251  it->second->setName(newName);
1252  std::swap(granteeMap_[to_upper(newName)], it->second);
1253  granteeMap_.erase(it);
1254  }
1255 
1256  // Also rename in objectDescriptorMap_
1257  for (auto d = objectDescriptorMap_.begin(); d != objectDescriptorMap_.end(); ++d) {
1258  if (d->second->roleName == roleName) {
1259  d->second->roleName = newName;
1260  }
1261  }
1262 }
1263 
1264 void SysCatalog::renameUser(std::string const& old_name, std::string const& new_name) {
1265  using namespace std::string_literals;
1266  sys_write_lock write_lock(this);
1268 
1269  UserMetadata old_user;
1270  if (!getMetadataForUser(old_name, old_user)) {
1271  std::string const loggable = g_log_user_id ? std::string("") : old_name + ' ';
1272  throw std::runtime_error("User " + loggable + "doesn't exist.");
1273  }
1274 
1275  UserMetadata new_user;
1276  if (getMetadataForUser(new_name, new_user)) {
1277  throw std::runtime_error("User " + new_user.userLoggable() + " already exists.");
1278  }
1279 
1280  if (getGrantee(new_name)) {
1281  std::string const loggable = g_log_user_id ? std::string("") : new_name + ' ';
1282  throw runtime_error(
1283  "Username " + loggable +
1284  "is same as one of existing grantees. User and role names should be unique.");
1285  }
1286 
1287  // Temporary user.
1288  if (old_user.is_temporary) {
1289  auto userit = temporary_users_by_name_.find(old_name);
1290  CHECK(userit != temporary_users_by_name_.end());
1291  auto node = temporary_users_by_name_.extract(userit);
1292  node.key() = new_name;
1293  temporary_users_by_name_.insert(std::move(node));
1294  userit->second->userName = new_name;
1295  updateUserRoleName(old_name, new_name);
1296  return;
1297  }
1298 
1299  // Normal user.
1300  auto transaction_streamer = yieldTransactionStreamer();
1301  auto failure_handler = [] {};
1302  auto success_handler = [this, &old_name, &new_name] {
1303  updateUserRoleName(old_name, new_name);
1304  };
1305  auto q1 = {"UPDATE mapd_users SET name=?1 where name=?2;"s, new_name, old_name};
1306  auto q2 = {"UPDATE mapd_object_permissions set roleName=?1 WHERE roleName=?2;"s,
1307  new_name,
1308  old_name};
1309  auto q3 = {"UPDATE mapd_roles set userName=?1 WHERE userName=?2;"s, new_name, old_name};
1310  transaction_streamer(sqliteConnector_, success_handler, failure_handler, q1, q2, q3);
1311 }
1312 
1313 void SysCatalog::renameDatabase(std::string const& old_name,
1314  std::string const& new_name) {
1315  using namespace std::string_literals;
1316  sys_write_lock write_lock(this);
1318 
1319  DBMetadata new_db;
1320  if (getMetadataForDB(new_name, new_db)) {
1321  throw std::runtime_error("Database " + new_name + " already exists.");
1322  }
1323  if (to_upper(new_name) == to_upper(shared::kSystemCatalogName)) {
1324  throw std::runtime_error("Database name " + new_name + "is reserved.");
1325  }
1326 
1327  DBMetadata old_db;
1328  if (!getMetadataForDB(old_name, old_db)) {
1329  throw std::runtime_error("Database " + old_name + " does not exists.");
1330  }
1331 
1332  removeCatalog(old_db.dbName);
1333 
1334  std::string old_catalog_path, new_catalog_path;
1335  std::tie(old_catalog_path, new_catalog_path) =
1336  duplicateAndRenameCatalog(old_name, new_name);
1337 
1338  auto transaction_streamer = yieldTransactionStreamer();
1339  auto failure_handler = [this, new_catalog_path] {
1340  removeCatalogByFullPath(new_catalog_path);
1341  };
1342  auto success_handler = [this, old_catalog_path] {
1343  removeCatalogByFullPath(old_catalog_path);
1344  };
1345 
1346  auto q1 = {"UPDATE mapd_databases SET name=?1 WHERE name=?2;"s, new_name, old_name};
1347  auto q2 = {
1348  "UPDATE mapd_object_permissions SET objectName=?1 WHERE objectNAME=?2 and (objectPermissionsType=?3 or objectId = -1) and dbId=?4;"s,
1349  new_name,
1350  old_name,
1352  std::to_string(old_db.dbId)};
1353 
1354  transaction_streamer(sqliteConnector_, success_handler, failure_handler, q1, q2);
1355 }
1356 
1357 void SysCatalog::createDatabase(const string& name, int owner) {
1358  sys_write_lock write_lock(this);
1360 
1361  DBMetadata db;
1362  if (getMetadataForDB(name, db)) {
1363  throw runtime_error("Database " + name + " already exists.");
1364  }
1366  throw runtime_error("Database name " + name + " is reserved.");
1367  }
1368 
1369  std::unique_ptr<SqliteConnector> dbConn(
1370  new SqliteConnector(name, basePath_ + "/" + shared::kCatalogDirectoryName + "/"));
1371  // NOTE(max): it's okay to run this in a separate transaction. If we fail later
1372  // we delete the database anyways.
1373  // If we run it in the same transaction as SysCatalog functions, then Catalog
1374  // constructor won't find the tables we have just created.
1375  dbConn->query("BEGIN TRANSACTION");
1376  try {
1377  dbConn->query(
1378  "CREATE TABLE mapd_tables (tableid integer primary key, name text unique, userid "
1379  "integer, ncolumns integer, "
1380  "isview boolean, "
1381  "fragments text, frag_type integer, max_frag_rows integer, max_chunk_size "
1382  "bigint, "
1383  "frag_page_size integer, "
1384  "max_rows bigint, partitions text, shard_column_id integer, shard integer, "
1385  "sort_column_id integer default 0, storage_type text default '', "
1386  "max_rollback_epochs integer default -1, "
1387  "is_system_table boolean default 0, "
1388  "num_shards integer, key_metainfo TEXT, version_num "
1389  "BIGINT DEFAULT 1) ");
1390  dbConn->query(
1391  "CREATE TABLE mapd_columns (tableid integer references mapd_tables, columnid "
1392  "integer, name text, coltype "
1393  "integer, colsubtype integer, coldim integer, colscale integer, is_notnull "
1394  "boolean, compression integer, "
1395  "comp_param integer, size integer, chunks text, is_systemcol boolean, "
1396  "is_virtualcol boolean, virtual_expr "
1397  "text, is_deletedcol boolean, version_num BIGINT, default_value text, "
1398  "primary key(tableid, columnid), unique(tableid, name))");
1399  dbConn->query(
1400  "CREATE TABLE mapd_views (tableid integer references mapd_tables, sql text)");
1401  dbConn->query(
1402  "CREATE TABLE mapd_dashboards (id integer primary key autoincrement, name text , "
1403  "userid integer references mapd_users, state text, image_hash text, update_time "
1404  "timestamp, "
1405  "metadata text, UNIQUE(userid, name) )");
1406  dbConn->query(
1407  "CREATE TABLE mapd_links (linkid integer primary key, userid integer references "
1408  "mapd_users, "
1409  "link text unique, view_state text, update_time timestamp, view_metadata text)");
1410  dbConn->query(
1411  "CREATE TABLE mapd_dictionaries (dictid integer primary key, name text unique, "
1412  "nbits int, is_shared boolean, "
1413  "refcount int, version_num BIGINT DEFAULT 1)");
1414  dbConn->query(
1415  "CREATE TABLE mapd_logical_to_physical(logical_table_id integer, "
1416  "physical_table_id "
1417  "integer)");
1418  dbConn->query("CREATE TABLE mapd_record_ownership_marker (dummy integer)");
1419  dbConn->query_with_text_params(
1420  "INSERT INTO mapd_record_ownership_marker (dummy) VALUES (?1)",
1421  std::vector<std::string>{std::to_string(owner)});
1422 
1423  if (g_enable_fsi) {
1424  dbConn->query(Catalog::getForeignServerSchema());
1425  dbConn->query(Catalog::getForeignTableSchema());
1426  }
1427  dbConn->query(Catalog::getCustomExpressionsSchema());
1428  } catch (const std::exception&) {
1429  dbConn->query("ROLLBACK TRANSACTION");
1430  boost::filesystem::remove(basePath_ + "/" + shared::kCatalogDirectoryName + "/" +
1431  name);
1432  throw;
1433  }
1434  dbConn->query("END TRANSACTION");
1435 
1436  std::shared_ptr<Catalog> cat;
1437  // Now update SysCatalog with privileges and the new database
1438  sqliteConnector_->query("BEGIN TRANSACTION");
1439  try {
1440  sqliteConnector_->query_with_text_param(
1441  "INSERT INTO mapd_databases (name, owner) VALUES (?, " + std::to_string(owner) +
1442  ")",
1443  name);
1444  CHECK(getMetadataForDB(name, db));
1445 
1446  cat = getCatalog(db, true);
1447 
1448  if (owner != shared::kRootUserId) {
1450  object.loadKey(*cat);
1451  UserMetadata user;
1452  CHECK(getMetadataForUserById(owner, user));
1453  grantAllOnDatabase_unsafe(user.userName, object, *cat);
1454  }
1455  } catch (const std::exception&) {
1456  sqliteConnector_->query("ROLLBACK TRANSACTION");
1457  boost::filesystem::remove(basePath_ + "/" + shared::kCatalogDirectoryName + "/" +
1458  name);
1459  throw;
1460  }
1461  sqliteConnector_->query("END TRANSACTION");
1462 
1463  // force a migration on the new database
1464  removeCatalog(name);
1465  cat = getCatalog(db, false);
1466 
1467  if (g_enable_fsi) {
1468  try {
1469  cat->createDefaultServersIfNotExists();
1470  } catch (...) {
1471  boost::filesystem::remove(basePath_ + "/" + shared::kCatalogDirectoryName + "/" +
1472  name);
1473  throw;
1474  }
1475  }
1476 }
1477 
1479  auto cat = getCatalog(db, false);
1480  cat->eraseDbPhysicalData();
1481  sys_write_lock write_lock(this);
1483  sqliteConnector_->query("BEGIN TRANSACTION");
1484  try {
1485  // remove this database ID from any users that have it set as their default database
1486  sqliteConnector_->query_with_text_param(
1487  "UPDATE mapd_users SET default_db = NULL WHERE default_db = ?",
1488  std::to_string(db.dbId));
1489  /* revoke object privileges to all tables of the database being dropped */
1490  const auto tables = cat->getAllTableMetadata();
1491  for (const auto table : tables) {
1492  if (table->shard >= 0) {
1493  // skip shards, they're not standalone tables
1494  continue;
1495  }
1497  DBObject(table->tableName, TableDBObjectType), cat.get());
1498  }
1499  const auto dashboards = cat->getAllDashboardsMetadata();
1500  for (const auto dashboard : dashboards) {
1502  DBObject(dashboard->dashboardId, DashboardDBObjectType), cat.get());
1503  }
1504  /* revoke object privileges to the database being dropped */
1505  for (const auto& grantee : granteeMap_) {
1506  if (grantee.second->hasAnyPrivilegesOnDb(db.dbId, true)) {
1508  grantee.second->getName(), db.dbId, grantee.second.get());
1509  }
1510  }
1511  sqliteConnector_->query_with_text_param("DELETE FROM mapd_databases WHERE dbid = ?",
1512  std::to_string(db.dbId));
1513  cat->eraseDbMetadata();
1514  removeCatalog(db.dbName);
1515  } catch (const std::exception&) {
1516  sqliteConnector_->query("ROLLBACK TRANSACTION");
1517  throw;
1518  }
1519  sqliteConnector_->query("END TRANSACTION");
1520 }
1521 
1522 // checkPasswordForUser() with no EE code
1523 bool SysCatalog::checkPasswordForUser(const std::string& passwd,
1524  std::string& name,
1525  UserMetadata& user) {
1526  return checkPasswordForUserImpl(passwd, name, user);
1527 }
1528 
1529 bool SysCatalog::checkPasswordForUserImpl(const std::string& passwd,
1530  std::string& name,
1531  UserMetadata& user) {
1532  sys_read_lock read_lock(this);
1533  if (!getMetadataForUser(name, user)) {
1534  // Check password against some fake hash just to waste time so that response times
1535  // for invalid password and invalid user are similar and a caller can't say the
1536  // difference
1537  char fake_hash[BCRYPT_HASHSIZE];
1538  CHECK(bcrypt_gensalt(-1, fake_hash) == 0);
1539  bcrypt_checkpw(passwd.c_str(), fake_hash);
1540  LOG(WARNING) << "Local login failed";
1541  return false;
1542  }
1543  int pwd_check_result = bcrypt_checkpw(passwd.c_str(), user.passwd_hash.c_str());
1544  // if the check fails there is a good chance that data on disc is broken
1545  CHECK(pwd_check_result >= 0);
1546  return pwd_check_result == 0;
1547 }
1548 
1549 static bool parseUserMetadataFromSQLite(const std::unique_ptr<SqliteConnector>& conn,
1550  UserMetadata& user,
1551  int row) {
1552  int numRows = conn->getNumRows();
1553  if (numRows == 0) {
1554  return false;
1555  }
1556  user.userId = conn->getData<int>(row, 0);
1557  user.userName = conn->getData<string>(row, 1);
1558  user.passwd_hash = conn->getData<string>(row, 2);
1559  user.isSuper = conn->getData<bool>(row, 3);
1560  user.defaultDbId = conn->isNull(row, 4) ? -1 : conn->getData<int>(row, 4);
1561  if (conn->isNull(row, 5)) {
1562  LOG(WARNING)
1563  << "User property 'can_login' not set for user " << user.userLoggable()
1564  << ". Disabling login ability. Set the users login ability with \"ALTER USER "
1565  << (g_log_user_id ? std::string("[username]") : user.userName)
1566  << " (can_login='true');\".";
1567  }
1568  user.can_login = conn->isNull(row, 5) ? false : conn->getData<bool>(row, 5);
1569  return true;
1570 }
1571 
1573  sys_read_lock read_lock(this);
1575  sqliteConnector_->query_with_text_param(
1576  "SELECT userid, name, passwd_hash, issuper, default_db, can_login FROM mapd_users "
1577  "WHERE name = ?",
1578  name);
1579  int numRows = sqliteConnector_->getNumRows();
1580  if (numRows == 0) {
1581  auto userit = temporary_users_by_name_.find(name);
1582  if (userit != temporary_users_by_name_.end()) {
1583  user = *userit->second;
1584  return true;
1585  } else {
1586  return false;
1587  }
1588  }
1590 }
1591 
1592 bool SysCatalog::getMetadataForUserById(const int32_t idIn, UserMetadata& user) {
1594  sqliteConnector_->query_with_text_param(
1595  "SELECT userid, name, passwd_hash, issuper, default_db, can_login FROM mapd_users "
1596  "WHERE userid = ?",
1597  std::to_string(idIn));
1598  int numRows = sqliteConnector_->getNumRows();
1599  if (numRows == 0) {
1600  auto userit = temporary_users_by_id_.find(idIn);
1601  if (userit != temporary_users_by_id_.end()) {
1602  user = *userit->second;
1603  return true;
1604  } else {
1605  return false;
1606  }
1607  }
1609 }
1610 
1611 list<DBMetadata> SysCatalog::getAllDBMetadata() {
1613  sqliteConnector_->query("SELECT dbid, name, owner FROM mapd_databases");
1614  int numRows = sqliteConnector_->getNumRows();
1615  list<DBMetadata> db_list;
1616  for (int r = 0; r < numRows; ++r) {
1617  DBMetadata db;
1618  db.dbId = sqliteConnector_->getData<int>(r, 0);
1619  db.dbName = sqliteConnector_->getData<string>(r, 1);
1620  db.dbOwner = sqliteConnector_->getData<int>(r, 2);
1621  db_list.push_back(db);
1622  }
1623  return db_list;
1624 }
1625 
1626 namespace {
1627 
1628 auto get_users(SysCatalog& syscat,
1629  std::unique_ptr<SqliteConnector>& sqliteConnector,
1630  const int32_t dbId = -1) {
1631  // Normal users.
1632  sqliteConnector->query(
1633  "SELECT userid, name, passwd_hash, issuper, default_db, can_login FROM mapd_users");
1634  int numRows = sqliteConnector->getNumRows();
1635  list<UserMetadata> user_list;
1636  const bool return_all_users = dbId == -1;
1637  auto has_any_privilege = [&return_all_users, &dbId, &syscat](const std::string& name) {
1638  if (!return_all_users) {
1639  const auto grantee = syscat.getUserGrantee(name);
1640  return grantee ? grantee->hasAnyPrivilegesOnDb(dbId, false) : false;
1641  }
1642  return true;
1643  };
1644  for (int r = 0; r < numRows; ++r) {
1646  parseUserMetadataFromSQLite(sqliteConnector, user, r);
1647  if (has_any_privilege(user.userName)) {
1648  user_list.emplace_back(std::move(user));
1649  }
1650  }
1651 
1652  // Temporary users.
1653  for (const auto& [id, userptr] : syscat.temporary_users_by_id_) {
1654  if (has_any_privilege(userptr->userName)) {
1655  user_list.emplace_back(*userptr);
1656  }
1657  }
1658 
1659  return user_list;
1660 }
1661 
1662 } // namespace
1663 
1664 list<UserMetadata> SysCatalog::getAllUserMetadata(const int64_t dbId) {
1665  // this call is to return users that have some form of permissions to objects in the db
1666  // sadly mapd_object_permissions table is also misused to manage user roles.
1668  return get_users(*this, sqliteConnector_, dbId);
1669 }
1670 
1671 list<UserMetadata> SysCatalog::getAllUserMetadata() {
1673  return get_users(*this, sqliteConnector_);
1674 }
1675 
1676 void SysCatalog::getMetadataWithDefaultDB(std::string& dbname,
1677  const std::string& username,
1679  UserMetadata& user_meta) {
1680  sys_read_lock read_lock(this);
1681  if (!getMetadataForUser(username, user_meta)) {
1682  throw std::runtime_error("Invalid credentials.");
1683  }
1684 
1685  if (!dbname.empty()) {
1686  if (!getMetadataForDB(dbname, db_meta)) {
1687  throw std::runtime_error("Database name " + dbname + " does not exist.");
1688  }
1689  // loaded the requested database
1690  } else {
1691  if (user_meta.defaultDbId != -1) {
1692  if (!getMetadataForDBById(user_meta.defaultDbId, db_meta)) {
1693  std::string loggable = g_log_user_id ? std::string("") : ' ' + user_meta.userName;
1694  throw std::runtime_error(
1695  "Server error: User #" + std::to_string(user_meta.userId) + loggable +
1696  " has invalid default_db #" + std::to_string(user_meta.defaultDbId) +
1697  " which does not exist.");
1698  }
1699  dbname = db_meta.dbName;
1700  // loaded the user's default database
1701  } else {
1702  if (!getMetadataForDB(shared::kDefaultDbName, db_meta)) {
1703  throw std::runtime_error(std::string("Database ") + shared::kDefaultDbName +
1704  " does not exist.");
1705  }
1706  dbname = shared::kDefaultDbName;
1707  // loaded the mapd database by default
1708  }
1709  }
1710 }
1711 
1713  sys_read_lock read_lock(this);
1715  sqliteConnector_->query_with_text_param(
1716  "SELECT dbid, name, owner FROM mapd_databases WHERE name = ?", name);
1717  int numRows = sqliteConnector_->getNumRows();
1718  if (numRows == 0) {
1719  return false;
1720  }
1721  db.dbId = sqliteConnector_->getData<int>(0, 0);
1722  db.dbName = sqliteConnector_->getData<string>(0, 1);
1723  db.dbOwner = sqliteConnector_->getData<int>(0, 2);
1724  return true;
1725 }
1726 
1727 bool SysCatalog::getMetadataForDBById(const int32_t idIn, DBMetadata& db) {
1729  sqliteConnector_->query_with_text_param(
1730  "SELECT dbid, name, owner FROM mapd_databases WHERE dbid = ?",
1731  std::to_string(idIn));
1732  int numRows = sqliteConnector_->getNumRows();
1733  if (numRows == 0) {
1734  return false;
1735  }
1736  db.dbId = sqliteConnector_->getData<int>(0, 0);
1737  db.dbName = sqliteConnector_->getData<string>(0, 1);
1738  db.dbOwner = sqliteConnector_->getData<int>(0, 2);
1739  return true;
1740 }
1741 
1743  DBSummaryList ret;
1744 
1745  std::list<Catalog_Namespace::DBMetadata> db_list = getAllDBMetadata();
1746  std::list<Catalog_Namespace::UserMetadata> user_list = getAllUserMetadata();
1747 
1748  for (auto d : db_list) {
1749  DBObject dbObject(d.dbName, DatabaseDBObjectType);
1750  dbObject.loadKey();
1752  if (!checkPrivileges(user, std::vector<DBObject>{dbObject})) {
1753  continue;
1754  }
1755  for (auto u : user_list) {
1756  if (d.dbOwner == u.userId) {
1757  ret.emplace_back(DBSummary{d.dbName, u.userName});
1758  break;
1759  }
1760  }
1761  }
1762 
1763  return ret;
1764 }
1765 
1767  const std::string& objectName,
1769  const Catalog_Namespace::Catalog& catalog,
1770  int32_t objectId) {
1771  sys_write_lock write_lock(this);
1773 
1774  DBObject object =
1775  objectId == -1 ? DBObject(objectName, type) : DBObject(objectId, type);
1776  object.loadKey(catalog);
1777  switch (type) {
1778  case TableDBObjectType:
1779  object.setPrivileges(AccessPrivileges::ALL_TABLE);
1780  break;
1781  case DashboardDBObjectType:
1782  object.setPrivileges(AccessPrivileges::ALL_DASHBOARD);
1783  break;
1784  case ServerDBObjectType:
1785  object.setPrivileges(AccessPrivileges::ALL_SERVER);
1786  break;
1787  default:
1788  object.setPrivileges(AccessPrivileges::ALL_DATABASE);
1789  break;
1790  }
1791  object.setOwner(user.userId);
1792  sqliteConnector_->query("BEGIN TRANSACTION");
1793  try {
1794  if (!user.isSuper) { // no need to grant to suser, has all privs by default
1795  grantDBObjectPrivileges_unsafe(user.userName, object, catalog);
1796  auto* grantee = instance().getUserGrantee(user.userName);
1797  if (!grantee) {
1798  throw runtime_error("Cannot create DBObject. User " + user.userLoggable() +
1799  " does not exist.");
1800  }
1801  grantee->grantPrivileges(object);
1802  }
1803  } catch (std::exception& e) {
1804  sqliteConnector_->query("ROLLBACK TRANSACTION");
1805  throw;
1806  }
1807  sqliteConnector_->query("END TRANSACTION");
1808 }
1809 
1810 void SysCatalog::renameDBObject(const std::string& objectName,
1811  const std::string& newName,
1813  int32_t objectId,
1814  const Catalog_Namespace::Catalog& catalog) {
1815  sys_write_lock write_lock(this);
1816  DBObject new_object(newName, type);
1817  DBObjectKey key;
1818  key.dbId = catalog.getCurrentDB().dbId;
1819  key.objectId = objectId;
1820  key.permissionType = type;
1821  new_object.setObjectKey(key);
1822  auto objdescs =
1823  getMetadataForObject(key.dbId, static_cast<int32_t>(type), key.objectId);
1824  for (auto obj : objdescs) {
1825  Grantee* grnt = getGrantee(obj->roleName);
1826  if (grnt) {
1827  grnt->renameDbObject(new_object);
1828  }
1829  }
1830  renameObjectsInDescriptorMap(new_object, catalog);
1831 }
1832 
1834  const vector<string>& grantees,
1835  const vector<DBObject>& objects,
1836  const Catalog_Namespace::Catalog& catalog) {
1837  for (const auto& grantee : grantees) {
1838  for (const auto& object : objects) {
1839  grantDBObjectPrivileges_unsafe(grantee, object, catalog);
1840  }
1841  }
1842 }
1843 
1844 // GRANT INSERT ON TABLE payroll_table TO payroll_dept_role;
1846  const std::string& granteeName,
1847  DBObject object,
1848  const Catalog_Namespace::Catalog& catalog) {
1849  object.loadKey(catalog);
1850  CHECK(object.valid());
1851  if (object.getPrivileges().hasPermission(DatabasePrivileges::ALL) &&
1852  object.getObjectKey().permissionType == DatabaseDBObjectType) {
1853  return grantAllOnDatabase_unsafe(granteeName, object, catalog);
1854  }
1855 
1856  sys_write_lock write_lock(this);
1857 
1858  UserMetadata user_meta;
1859  bool is_temporary_user{false};
1860  if (instance().getMetadataForUser(granteeName, user_meta)) {
1861  if (user_meta.isSuper) {
1862  // super doesn't have explicit privileges so nothing to do
1863  return;
1864  }
1865  is_temporary_user = user_meta.is_temporary;
1866  }
1867  auto* grantee = instance().getGrantee(granteeName);
1868  if (!grantee) {
1869  throw runtime_error("Request to grant privileges to " + granteeName +
1870  " failed because role or user with this name does not exist.");
1871  }
1872  grantee->grantPrivileges(object);
1873 
1874  /* apply grant privileges statement to sqlite DB */
1875  std::vector<std::string> objectKey = object.toString();
1876  object.resetPrivileges();
1877  grantee->getPrivileges(object, true);
1878 
1879  if (!is_temporary_user) {
1882  sqliteConnector_, granteeName, grantee->isUser(), object);
1883  }
1884  updateObjectDescriptorMap(granteeName, object, grantee->isUser(), catalog);
1885 }
1886 
1887 void SysCatalog::grantAllOnDatabase_unsafe(const std::string& roleName,
1888  DBObject& object,
1889  const Catalog_Namespace::Catalog& catalog) {
1890  // It's a separate use case because it's easier for implementation to convert ALL ON
1891  // DATABASE into ALL ON DASHBOARDS, ALL ON VIEWS and ALL ON TABLES
1892  // Add DB Access privileges
1893  DBObject tmp_object = object;
1896  grantDBObjectPrivileges_unsafe(roleName, tmp_object, catalog);
1899  grantDBObjectPrivileges_unsafe(roleName, tmp_object, catalog);
1902  grantDBObjectPrivileges_unsafe(roleName, tmp_object, catalog);
1904  tmp_object.setPermissionType(ViewDBObjectType);
1905  grantDBObjectPrivileges_unsafe(roleName, tmp_object, catalog);
1906 
1907  if (g_enable_fsi) {
1910  grantDBObjectPrivileges_unsafe(roleName, tmp_object, catalog);
1911  }
1912 
1915  grantDBObjectPrivileges_unsafe(roleName, tmp_object, catalog);
1916  return;
1917 }
1918 
1920  const vector<string>& grantees,
1921  const vector<DBObject>& objects,
1922  const Catalog_Namespace::Catalog& catalog) {
1923  for (const auto& grantee : grantees) {
1924  for (const auto& object : objects) {
1925  revokeDBObjectPrivileges_unsafe(grantee, object, catalog);
1926  }
1927  }
1928 }
1929 
1931  vector<DBObject>& objects,
1932  Catalog_Namespace::Catalog* catalog) {
1933  for (const auto& object : objects) {
1934  revokeDBObjectPrivilegesFromAll_unsafe(object, catalog);
1935  }
1936 }
1937 
1938 // REVOKE INSERT ON TABLE payroll_table FROM payroll_dept_role;
1940  const std::string& granteeName,
1941  DBObject object,
1942  const Catalog_Namespace::Catalog& catalog) {
1943  sys_write_lock write_lock(this);
1944 
1945  UserMetadata user_meta;
1946  bool is_temporary_user{false};
1947  if (instance().getMetadataForUser(granteeName, user_meta)) {
1948  if (user_meta.isSuper) {
1949  // super doesn't have explicit privileges so nothing to do
1950  return;
1951  }
1952  is_temporary_user = user_meta.is_temporary;
1953  }
1954  auto* grantee = getGrantee(granteeName);
1955  if (!grantee) {
1956  throw runtime_error("Request to revoke privileges from " + granteeName +
1957  " failed because role or user with this name does not exist.");
1958  }
1959  object.loadKey(catalog);
1960 
1961  if (object.getPrivileges().hasPermission(DatabasePrivileges::ALL) &&
1962  object.getObjectKey().permissionType == DatabaseDBObjectType) {
1963  return revokeAllOnDatabase_unsafe(granteeName, object.getObjectKey().dbId, grantee);
1964  }
1965 
1966  auto ret_object = grantee->revokePrivileges(object);
1967  if (ret_object) {
1968  if (!is_temporary_user) {
1971  sqliteConnector_, granteeName, grantee->isUser(), *ret_object);
1972  }
1973  updateObjectDescriptorMap(granteeName, *ret_object, grantee->isUser(), catalog);
1974  } else {
1975  if (!is_temporary_user) {
1977  deleteObjectPrivileges(sqliteConnector_, granteeName, grantee->isUser(), object);
1978  }
1979  deleteObjectDescriptorMap(granteeName, object, catalog);
1980  }
1981 }
1982 
1983 void SysCatalog::revokeAllOnDatabase_unsafe(const std::string& roleName,
1984  int32_t dbId,
1985  Grantee* grantee) {
1986  bool is_temporary =
1987  (temporary_users_by_name_.find(roleName) != temporary_users_by_name_.end());
1988  if (!is_temporary) {
1990  sqliteConnector_->query_with_text_params(
1991  "DELETE FROM mapd_object_permissions WHERE roleName = ?1 and dbId = ?2",
1992  std::vector<std::string>{roleName, std::to_string(dbId)});
1993  }
1994  grantee->revokeAllOnDatabase(dbId);
1995  for (auto d = objectDescriptorMap_.begin(); d != objectDescriptorMap_.end();) {
1996  if (d->second->roleName == roleName && d->second->dbId == dbId) {
1997  d = objectDescriptorMap_.erase(d);
1998  } else {
1999  d++;
2000  }
2001  }
2002 }
2003 
2005  Catalog* catalog) {
2006  sys_write_lock write_lock(this);
2007  dbObject.loadKey(*catalog);
2008  auto privs = (dbObject.getObjectKey().permissionType == TableDBObjectType)
2013  dbObject.setPrivileges(privs);
2014  for (const auto& grantee : granteeMap_) {
2015  if (grantee.second->findDbObject(dbObject.getObjectKey(), true)) {
2016  revokeDBObjectPrivileges_unsafe(grantee.second->getName(), dbObject, *catalog);
2017  }
2018  }
2019 }
2020 
2022  DBObject object,
2023  const Catalog_Namespace::Catalog& catalog) {
2024  sys_read_lock read_lock(this);
2025 
2026  auto* grantee = instance().getUserGrantee(user.userName);
2027  if (grantee) {
2028  object.loadKey(catalog);
2029  auto* found_object = grantee->findDbObject(object.getObjectKey(), false);
2030  if (found_object && found_object->getOwner() == user.userId) {
2031  return true;
2032  }
2033  }
2034  return false;
2035 }
2036 
2038  const UserMetadata& previous_owner,
2039  DBObject object,
2040  const Catalog_Namespace::Catalog& catalog,
2041  bool revoke_privileges) {
2042  sys_write_lock write_lock(this);
2043  if (new_owner.is_temporary || previous_owner.is_temporary) {
2044  throw std::runtime_error("ownership change not allowed for temporary user(s)");
2045  }
2047  object.loadKey(catalog);
2048  switch (object.getType()) {
2049  case TableDBObjectType:
2050  object.setPrivileges(AccessPrivileges::ALL_TABLE);
2051  break;
2052  case DashboardDBObjectType:
2053  object.setPrivileges(AccessPrivileges::ALL_DASHBOARD);
2054  break;
2055  case ServerDBObjectType:
2056  object.setPrivileges(AccessPrivileges::ALL_SERVER);
2057  break;
2058  case DatabaseDBObjectType:
2059  object.setPrivileges(AccessPrivileges::ALL_DATABASE);
2060  break;
2061  case ViewDBObjectType:
2062  object.setPrivileges(AccessPrivileges::ALL_VIEW);
2063  break;
2064  default:
2065  UNREACHABLE(); // unkown object type
2066  break;
2067  }
2068  sqliteConnector_->query("BEGIN TRANSACTION");
2069  try {
2070  if (!new_owner.isSuper) { // no need to grant to suser, has all privs by default
2071  grantDBObjectPrivileges_unsafe(new_owner.userName, object, catalog);
2072  }
2073  if (!previous_owner.isSuper && revoke_privileges) { // no need to revoke from suser
2074  revokeDBObjectPrivileges_unsafe(previous_owner.userName, object, catalog);
2075  }
2076  auto object_key = object.getObjectKey();
2077  sqliteConnector_->query_with_text_params(
2078  "UPDATE mapd_object_permissions SET objectOwnerId = ? WHERE dbId = ? AND "
2079  "objectId = ? AND objectPermissionsType = ?",
2080  std::vector<std::string>{std::to_string(new_owner.userId),
2081  std::to_string(object_key.dbId),
2082  std::to_string(object_key.objectId),
2083  std::to_string(object_key.permissionType)});
2084 
2085  for (const auto& [user_or_role, grantee] : granteeMap_) {
2086  grantee->reassignObjectOwner(object_key, new_owner.userId);
2087  }
2088 
2089  for (const auto& [map_object_key, map_object_descriptor] : objectDescriptorMap_) {
2090  if (map_object_descriptor->objectId == object_key.objectId &&
2091  map_object_descriptor->objectType == object_key.permissionType &&
2092  map_object_descriptor->dbId == object_key.dbId) {
2093  map_object_descriptor->objectOwnerId = new_owner.userId;
2094  }
2095  }
2096  } catch (std::exception& e) {
2097  sqliteConnector_->query("ROLLBACK TRANSACTION");
2099  throw;
2100  }
2101  sqliteConnector_->query("END TRANSACTION");
2102 }
2103 
2104 void SysCatalog::getDBObjectPrivileges(const std::string& granteeName,
2105  DBObject& object,
2106  const Catalog_Namespace::Catalog& catalog) const {
2107  sys_read_lock read_lock(this);
2108  UserMetadata user_meta;
2109 
2110  if (instance().getMetadataForUser(granteeName, user_meta)) {
2111  if (user_meta.isSuper) {
2112  throw runtime_error(
2113  "Request to show privileges from " + granteeName +
2114  " failed because user is super user and has all privileges by default.");
2115  }
2116  }
2117  auto* grantee = instance().getGrantee(granteeName);
2118  if (!grantee) {
2119  throw runtime_error("Request to show privileges for " + granteeName +
2120  " failed because role or user with this name does not exist.");
2121  }
2122  object.loadKey(catalog);
2123  grantee->getPrivileges(object, true);
2124 }
2125 
2126 void SysCatalog::createRole_unsafe(const std::string& roleName,
2127  const bool user_private_role,
2128  const bool is_temporary) {
2129  sys_write_lock write_lock(this);
2130 
2131  auto* grantee = getGrantee(roleName);
2132  if (grantee) {
2133  throw std::runtime_error("CREATE ROLE " + roleName +
2134  " failed because grantee with this name already exists.");
2135  }
2136  std::unique_ptr<Grantee> g;
2137  if (user_private_role) {
2138  g.reset(new User(roleName));
2139  } else {
2140  g.reset(new Role(roleName));
2141  }
2142  grantee = g.get();
2143  granteeMap_[to_upper(roleName)] = std::move(g);
2144 
2145  // NOTE (max): Why create an empty privileges record for a role?
2146  /* grant none privileges to this role and add it to sqlite DB */
2148  DBObjectKey objKey;
2149  // 0 is an id that does not exist
2150  objKey.dbId = 0;
2152  dbObject.setObjectKey(objKey);
2153  grantee->grantPrivileges(dbObject);
2154 
2155  if (!is_temporary) {
2158  sqliteConnector_, roleName, user_private_role, dbObject);
2159  }
2160 }
2161 
2162 void SysCatalog::dropRole_unsafe(const std::string& roleName, const bool is_temporary) {
2163  sys_write_lock write_lock(this);
2164 
2165  for (auto d = objectDescriptorMap_.begin(); d != objectDescriptorMap_.end();) {
2166  if (d->second->roleName == roleName) {
2167  d = objectDescriptorMap_.erase(d);
2168  } else {
2169  d++;
2170  }
2171  }
2172  // it may very well be a user "role", so keep it generic
2173  granteeMap_.erase(to_upper(roleName));
2174 
2175  if (!is_temporary) {
2177  sqliteConnector_->query_with_text_param("DELETE FROM mapd_roles WHERE roleName = ?",
2178  roleName);
2179  sqliteConnector_->query_with_text_param(
2180  "DELETE FROM mapd_object_permissions WHERE roleName = ?", roleName);
2181  }
2182 }
2183 
2184 void SysCatalog::grantRoleBatch_unsafe(const std::vector<std::string>& roles,
2185  const std::vector<std::string>& grantees) {
2186  for (const auto& role : roles) {
2187  for (const auto& grantee : grantees) {
2188  bool is_temporary_user{false};
2189  UserMetadata user;
2190  if (getMetadataForUser(grantee, user)) {
2191  is_temporary_user = user.is_temporary;
2192  }
2193  grantRole_unsafe(role, grantee, is_temporary_user);
2194  }
2195  }
2196 }
2197 
2198 // GRANT ROLE payroll_dept_role TO joe;
2199 void SysCatalog::grantRole_unsafe(const std::string& roleName,
2200  const std::string& granteeName,
2201  const bool is_temporary) {
2202  auto* rl = getRoleGrantee(roleName);
2203  if (!rl) {
2204  throw runtime_error("Request to grant role " + roleName +
2205  " failed because role with this name does not exist.");
2206  }
2207  auto* grantee = getGrantee(granteeName);
2208  if (!grantee) {
2209  throw runtime_error("Request to grant role " + roleName + " failed because grantee " +
2210  granteeName + " does not exist.");
2211  }
2212  sys_write_lock write_lock(this);
2213  if (!grantee->hasRole(rl, true)) {
2214  grantee->grantRole(rl);
2215  if (!is_temporary) {
2217  sqliteConnector_->query_with_text_params(
2218  "INSERT INTO mapd_roles(roleName, userName) VALUES (?, ?)",
2219  std::vector<std::string>{rl->getName(), grantee->getName()});
2220  }
2221  }
2222 }
2223 
2224 void SysCatalog::revokeRoleBatch_unsafe(const std::vector<std::string>& roles,
2225  const std::vector<std::string>& grantees) {
2226  for (const auto& role : roles) {
2227  for (const auto& grantee : grantees) {
2228  bool is_temporary_user{false};
2229  UserMetadata user;
2230  if (getMetadataForUser(grantee, user)) {
2231  is_temporary_user = user.is_temporary;
2232  }
2233  revokeRole_unsafe(role, grantee, is_temporary_user);
2234  }
2235  }
2236 }
2237 
2238 // REVOKE ROLE payroll_dept_role FROM joe;
2239 void SysCatalog::revokeRole_unsafe(const std::string& roleName,
2240  const std::string& granteeName,
2241  const bool is_temporary) {
2242  auto* rl = getRoleGrantee(roleName);
2243  if (!rl) {
2244  throw runtime_error("Request to revoke role " + roleName +
2245  " failed because role with this name does not exist.");
2246  }
2247  auto* grantee = getGrantee(granteeName);
2248  if (!grantee) {
2249  throw runtime_error("Request to revoke role from " + granteeName +
2250  " failed because grantee with this name does not exist.");
2251  }
2252  sys_write_lock write_lock(this);
2253  grantee->revokeRole(rl);
2254  if (!is_temporary) {
2256  sqliteConnector_->query_with_text_params(
2257  "DELETE FROM mapd_roles WHERE roleName = ? AND userName = ?",
2258  std::vector<std::string>{rl->getName(), grantee->getName()});
2259  }
2260 }
2261 
2262 // Update or add element in ObjectRoleDescriptorMap
2263 void SysCatalog::updateObjectDescriptorMap(const std::string& roleName,
2264  DBObject& object,
2265  bool roleType,
2267  bool present = false;
2268  auto privs = object.getPrivileges();
2269  sys_write_lock write_lock(this);
2270  auto range = objectDescriptorMap_.equal_range(
2271  std::to_string(cat.getCurrentDB().dbId) + ":" +
2272  std::to_string(object.getObjectKey().permissionType) + ":" +
2273  std::to_string(object.getObjectKey().objectId));
2274  for (auto d = range.first; d != range.second; ++d) {
2275  if (d->second->roleName == roleName) {
2276  // overwrite permissions
2277  d->second->privs = privs;
2278  present = true;
2279  }
2280  }
2281  if (!present) {
2282  auto od = std::make_unique<ObjectRoleDescriptor>();
2283  od->roleName = roleName;
2284  od->roleType = roleType;
2285  od->objectType = object.getObjectKey().permissionType;
2286  od->dbId = object.getObjectKey().dbId;
2287  od->objectId = object.getObjectKey().objectId;
2288  od->privs = object.getPrivileges();
2289  od->objectOwnerId = object.getOwner();
2290  od->objectName = object.getName();
2291  objectDescriptorMap_.insert(ObjectRoleDescriptorMap::value_type(
2292  std::to_string(od->dbId) + ":" + std::to_string(od->objectType) + ":" +
2293  std::to_string(od->objectId),
2294  std::move(od)));
2295  }
2296 }
2297 
2298 // rename object descriptors
2301  sys_write_lock write_lock(this);
2303  auto range = objectDescriptorMap_.equal_range(
2304  std::to_string(cat.getCurrentDB().dbId) + ":" +
2305  std::to_string(object.getObjectKey().permissionType) + ":" +
2306  std::to_string(object.getObjectKey().objectId));
2307  for (auto d = range.first; d != range.second; ++d) {
2308  // rename object
2309  d->second->objectName = object.getName();
2310  }
2311 
2312  sqliteConnector_->query("BEGIN TRANSACTION");
2313  try {
2314  sqliteConnector_->query_with_text_params(
2315  "UPDATE mapd_object_permissions SET objectName = ?1 WHERE "
2316  "dbId = ?2 AND objectId = ?3",
2317  std::vector<std::string>{object.getName(),
2319  std::to_string(object.getObjectKey().objectId)});
2320  } catch (const std::exception& e) {
2321  sqliteConnector_->query("ROLLBACK TRANSACTION");
2322  throw;
2323  }
2324  sqliteConnector_->query("END TRANSACTION");
2325 }
2326 
2327 // Remove user/role from ObjectRoleDescriptorMap
2328 void SysCatalog::deleteObjectDescriptorMap(const std::string& roleName) {
2329  sys_write_lock write_lock(this);
2330 
2331  for (auto d = objectDescriptorMap_.begin(); d != objectDescriptorMap_.end();) {
2332  if (d->second->roleName == roleName) {
2333  d = objectDescriptorMap_.erase(d);
2334  } else {
2335  d++;
2336  }
2337  }
2338 }
2339 
2340 // Remove element from ObjectRoleDescriptorMap
2341 void SysCatalog::deleteObjectDescriptorMap(const std::string& roleName,
2342  DBObject& object,
2343  const Catalog_Namespace::Catalog& cat) {
2344  sys_write_lock write_lock(this);
2345  auto range = objectDescriptorMap_.equal_range(
2346  std::to_string(cat.getCurrentDB().dbId) + ":" +
2347  std::to_string(object.getObjectKey().permissionType) + ":" +
2348  std::to_string(object.getObjectKey().objectId));
2349  for (auto d = range.first; d != range.second;) {
2350  // remove the entry
2351  if (d->second->roleName == roleName) {
2352  d = objectDescriptorMap_.erase(d);
2353  } else {
2354  d++;
2355  }
2356  }
2357 }
2358 
2360  std::vector<DBObject>& privObjects) {
2361  sys_read_lock read_lock(this);
2362  if (user.isSuper) {
2363  return true;
2364  }
2365  auto* user_rl = instance().getUserGrantee(user.userName);
2366  if (!user_rl) {
2367  throw runtime_error("Cannot check privileges. User " + user.userLoggable() +
2368  " does not exist.");
2369  }
2370  for (std::vector<DBObject>::iterator objectIt = privObjects.begin();
2371  objectIt != privObjects.end();
2372  ++objectIt) {
2373  if (!user_rl->hasAnyPrivileges(*objectIt, false)) {
2374  return false;
2375  }
2376  }
2377  return true;
2378 }
2379 
2381  const std::vector<DBObject>& privObjects) const {
2382  sys_read_lock read_lock(this);
2383  if (user.isSuper) {
2384  return true;
2385  }
2386 
2387  auto* user_rl = instance().getUserGrantee(user.userName);
2388  if (!user_rl) {
2389  throw runtime_error("Cannot check privileges. User " + user.userLoggable() +
2390  " does not exist.");
2391  }
2392  for (auto& object : privObjects) {
2393  if (!user_rl->checkPrivileges(object)) {
2394  return false;
2395  }
2396  }
2397  return true;
2398 }
2399 
2400 bool SysCatalog::checkPrivileges(const std::string& userName,
2401  const std::vector<DBObject>& privObjects) const {
2402  UserMetadata user;
2403  if (!instance().getMetadataForUser(userName, user)) {
2404  std::string const loggable = g_log_user_id ? std::string("") : userName + ' ';
2405  throw runtime_error("Request to check privileges for user " + loggable +
2406  "failed because user with this name does not exist.");
2407  }
2408  return (checkPrivileges(user, privObjects));
2409 }
2410 
2411 Grantee* SysCatalog::getGrantee(const std::string& name) const {
2412  sys_read_lock read_lock(this);
2413  auto grantee = granteeMap_.find(to_upper(name));
2414  if (grantee == granteeMap_.end()) { // check to make sure role exists
2415  return nullptr;
2416  }
2417  return grantee->second.get(); // returns pointer to role
2418 }
2419 
2420 Role* SysCatalog::getRoleGrantee(const std::string& name) const {
2421  return dynamic_cast<Role*>(getGrantee(name));
2422 }
2423 
2424 User* SysCatalog::getUserGrantee(const std::string& name) const {
2425  return dynamic_cast<User*>(getGrantee(name));
2426 }
2427 
2428 std::vector<ObjectRoleDescriptor*>
2429 SysCatalog::getMetadataForObject(int32_t dbId, int32_t dbType, int32_t objectId) const {
2430  sys_read_lock read_lock(this);
2431  std::vector<ObjectRoleDescriptor*> objectsList;
2432 
2433  auto range = objectDescriptorMap_.equal_range(std::to_string(dbId) + ":" +
2434  std::to_string(dbType) + ":" +
2435  std::to_string(objectId));
2436  for (auto d = range.first; d != range.second; ++d) {
2437  objectsList.push_back(d->second.get());
2438  }
2439  return objectsList; // return pointers to objects
2440 }
2441 
2442 std::vector<ObjectRoleDescriptor> SysCatalog::getMetadataForAllObjects() const {
2443  sys_read_lock read_lock(this);
2444  std::vector<ObjectRoleDescriptor> objects;
2445  for (const auto& entry : objectDescriptorMap_) {
2446  auto object_role = entry.second.get();
2447  if (object_role->dbId != 0 && !isDashboardSystemRole(object_role->roleName)) {
2448  objects.emplace_back(*object_role);
2449  }
2450  }
2451  return objects;
2452 }
2453 
2454 bool SysCatalog::isRoleGrantedToGrantee(const std::string& granteeName,
2455  const std::string& roleName,
2456  bool only_direct) const {
2457  sys_read_lock read_lock(this);
2458  if (roleName == granteeName) {
2459  return true;
2460  }
2461  bool is_role_granted = false;
2462  auto* target_role = instance().getRoleGrantee(roleName);
2463  auto has_role = [&](auto grantee_rl) {
2464  is_role_granted = target_role && grantee_rl->hasRole(target_role, only_direct);
2465  };
2466  if (auto* user_role = instance().getUserGrantee(granteeName); user_role) {
2467  has_role(user_role);
2468  } else if (auto* role = instance().getRoleGrantee(granteeName); role) {
2469  has_role(role);
2470  } else {
2471  CHECK(false);
2472  }
2473  return is_role_granted;
2474 }
2475 
2476 bool SysCatalog::isDashboardSystemRole(const std::string& roleName) const {
2477  return boost::algorithm::ends_with(roleName, SYSTEM_ROLE_TAG);
2478 }
2479 
2480 std::vector<std::string> SysCatalog::getRoles(const std::string& user_name,
2481  bool effective) {
2482  sys_read_lock read_lock(this);
2483  auto* grantee = getGrantee(user_name);
2484  if (!grantee) {
2485  throw std::runtime_error("user or role not found");
2486  }
2487  return grantee->getRoles(/*only_direct=*/!effective);
2488 }
2489 
2490 std::vector<std::string> SysCatalog::getRoles(const std::string& userName,
2491  const int32_t dbId) {
2492  sys_sqlite_lock sqlite_lock(this);
2493  std::string sql =
2494  "SELECT DISTINCT roleName FROM mapd_object_permissions WHERE "
2495  "objectPermissions<>0 "
2496  "AND roleType=0 AND dbId=" +
2497  std::to_string(dbId);
2498  sqliteConnector_->query(sql);
2499  int numRows = sqliteConnector_->getNumRows();
2500  std::vector<std::string> roles(0);
2501  for (int r = 0; r < numRows; ++r) {
2502  auto roleName = sqliteConnector_->getData<string>(r, 0);
2503  if (isRoleGrantedToGrantee(userName, roleName, false) &&
2504  !isDashboardSystemRole(roleName)) {
2505  roles.push_back(roleName);
2506  }
2507  }
2508  return roles;
2509 }
2510 
2511 std::vector<std::string> SysCatalog::getRoles(bool include_user_private_role,
2512  bool is_super,
2513  const std::string& user_name,
2514  bool ignore_deleted_user) {
2515  sys_read_lock read_lock(this);
2516  if (ignore_deleted_user) {
2517  // In certain cases, it is possible to concurrently call this method while the user is
2518  // being dropped. In such a case, return an empty result.
2519  UserMetadata user;
2520  if (!getMetadataForUser(user_name, user)) {
2521  return {};
2522  }
2523  }
2524  std::vector<std::string> roles;
2525  for (auto& grantee : granteeMap_) {
2526  if (!include_user_private_role && grantee.second->isUser()) {
2527  continue;
2528  }
2529  if (!is_super &&
2530  !isRoleGrantedToGrantee(user_name, grantee.second->getName(), false)) {
2531  continue;
2532  }
2533  if (isDashboardSystemRole(grantee.second->getName())) {
2534  continue;
2535  }
2536  roles.push_back(grantee.second->getName());
2537  }
2538  return roles;
2539 }
2540 
2541 std::set<std::string> SysCatalog::getCreatedRoles() const {
2542  sys_read_lock read_lock(this);
2543  std::set<std::string> roles; // Sorted for human readers.
2544  for (const auto& [key, grantee] : granteeMap_) {
2545  if (!grantee->isUser() && !isDashboardSystemRole(grantee->getName())) {
2546  roles.emplace(grantee->getName());
2547  }
2548  }
2549  return roles;
2550 }
2551 
2553  granteeMap_.clear();
2554  string roleQuery(
2555  "SELECT roleName, roleType, objectPermissionsType, dbId, objectId, "
2556  "objectPermissions, objectOwnerId, objectName "
2557  "from mapd_object_permissions");
2558  sqliteConnector_->query(roleQuery);
2559  size_t numRows = sqliteConnector_->getNumRows();
2560  std::vector<std::string> objectKeyStr(4);
2561  DBObjectKey objectKey;
2562  AccessPrivileges privs;
2563  bool userPrivateRole{false};
2564  for (size_t r = 0; r < numRows; ++r) {
2565  std::string roleName = sqliteConnector_->getData<string>(r, 0);
2566  userPrivateRole = sqliteConnector_->getData<bool>(r, 1);
2567  DBObjectType permissionType =
2568  static_cast<DBObjectType>(sqliteConnector_->getData<int>(r, 2));
2569  objectKeyStr[0] = sqliteConnector_->getData<string>(r, 2);
2570  objectKeyStr[1] = sqliteConnector_->getData<string>(r, 3);
2571  objectKeyStr[2] = sqliteConnector_->getData<string>(r, 4);
2572  objectKey = DBObjectKey::fromString(objectKeyStr, permissionType);
2573  privs.privileges = sqliteConnector_->getData<int>(r, 5);
2574  int32_t owner = sqliteConnector_->getData<int>(r, 6);
2575  std::string name = sqliteConnector_->getData<string>(r, 7);
2576 
2577  DBObject dbObject(objectKey, privs, owner);
2578  dbObject.setName(name);
2579  if (-1 == objectKey.objectId) {
2580  dbObject.setObjectType(DBObjectType::DatabaseDBObjectType);
2581  } else {
2582  dbObject.setObjectType(permissionType);
2583  }
2584 
2585  auto* rl = getGrantee(roleName);
2586  if (!rl) {
2587  std::unique_ptr<Grantee> g;
2588  if (userPrivateRole) {
2589  g.reset(new User(roleName));
2590  } else {
2591  g.reset(new Role(roleName));
2592  }
2593  rl = g.get();
2594  granteeMap_[to_upper(roleName)] = std::move(g);
2595  }
2596  rl->grantPrivileges(dbObject);
2597  }
2598 }
2599 
2600 void SysCatalog::populateRoleDbObjects(const std::vector<DBObject>& objects) {
2601  sys_write_lock write_lock(this);
2602  sys_sqlite_lock sqlite_lock(this);
2603  sqliteConnector_->query("BEGIN TRANSACTION");
2604  try {
2605  for (auto dbobject : objects) {
2606  UserMetadata user;
2607  CHECK(getMetadataForUserById(dbobject.getOwner(), user));
2608  auto* grantee = getUserGrantee(user.userName);
2609  if (grantee) {
2611  sqliteConnector_, grantee->getName(), true, dbobject);
2612  grantee->grantPrivileges(dbobject);
2613  }
2614  }
2615 
2616  } catch (const std::exception& e) {
2617  sqliteConnector_->query("ROLLBACK TRANSACTION");
2618  throw;
2619  }
2620  sqliteConnector_->query("END TRANSACTION");
2621 }
2622 
2624  std::vector<std::pair<std::string, std::string>> granteeRoles;
2625  string userRoleQuery("SELECT roleName, userName from mapd_roles");
2626  sqliteConnector_->query(userRoleQuery);
2627  size_t numRows = sqliteConnector_->getNumRows();
2628  for (size_t r = 0; r < numRows; ++r) {
2629  std::string roleName = sqliteConnector_->getData<string>(r, 0);
2630  std::string userName = sqliteConnector_->getData<string>(r, 1);
2631  // required for declared nomenclature before v4.0.0
2632  if ((boost::equals(roleName, "mapd_default_suser_role") &&
2633  boost::equals(userName, shared::kRootUsername)) ||
2634  (boost::equals(roleName, "mapd_default_user_role") &&
2635  !boost::equals(userName, "mapd_default_user_role"))) {
2636  // grouprole already exists with roleName==userName in mapd_roles table
2637  // ignore duplicate instances of userRole which exists before v4.0.0
2638  continue;
2639  }
2640  auto* rl = getGrantee(roleName);
2641  if (!rl) {
2642  throw runtime_error("Data inconsistency when building role map. Role " + roleName +
2643  " from db not found in the map.");
2644  }
2645  std::pair<std::string, std::string> roleVecElem(roleName, userName);
2646  granteeRoles.push_back(roleVecElem);
2647  }
2648 
2649  for (const auto& [roleName, granteeName] : granteeRoles) {
2650  auto* grantee = getGrantee(granteeName);
2651  if (!grantee) {
2652  throw runtime_error("Data inconsistency when building role map. Grantee " +
2653  granteeName + " not found in the map.");
2654  }
2655  if (granteeName == roleName) {
2656  continue;
2657  }
2658  Role* rl = dynamic_cast<Role*>(getGrantee(roleName));
2659  if (!rl) {
2660  throw runtime_error("Data inconsistency when building role map. Role " + roleName +
2661  " not found in the map.");
2662  }
2663  grantee->grantRole(rl);
2664  }
2665 }
2666 
2668  objectDescriptorMap_.clear();
2669  string objectQuery(
2670  "SELECT roleName, roleType, objectPermissionsType, dbId, objectId, "
2671  "objectPermissions, objectOwnerId, objectName "
2672  "from mapd_object_permissions");
2673  sqliteConnector_->query(objectQuery);
2674  size_t numRows = sqliteConnector_->getNumRows();
2675  for (size_t r = 0; r < numRows; ++r) {
2676  auto od = std::make_unique<ObjectRoleDescriptor>();
2677  od->roleName = sqliteConnector_->getData<string>(r, 0);
2678  od->roleType = sqliteConnector_->getData<bool>(r, 1);
2679  od->objectType = sqliteConnector_->getData<int>(r, 2);
2680  od->dbId = sqliteConnector_->getData<int>(r, 3);
2681  od->objectId = sqliteConnector_->getData<int>(r, 4);
2682  od->privs.privileges = sqliteConnector_->getData<int>(r, 5);
2683  od->objectOwnerId = sqliteConnector_->getData<int>(r, 6);
2684  od->objectName = sqliteConnector_->getData<string>(r, 7);
2685  objectDescriptorMap_.insert(ObjectRoleDescriptorMap::value_type(
2686  std::to_string(od->dbId) + ":" + std::to_string(od->objectType) + ":" +
2687  std::to_string(od->objectId),
2688  std::move(od)));
2689  }
2690 }
2691 
2692 template <typename F, typename... Args>
2693 void SysCatalog::execInTransaction(F&& f, Args&&... args) {
2694  sys_write_lock write_lock(this);
2695  sys_sqlite_lock sqlite_lock(this);
2696  sqliteConnector_->query("BEGIN TRANSACTION");
2697  try {
2698  (this->*f)(std::forward<Args>(args)...);
2699  } catch (std::exception&) {
2700  sqliteConnector_->query("ROLLBACK TRANSACTION");
2701  throw;
2702  }
2703  sqliteConnector_->query("END TRANSACTION");
2704 }
2705 
2706 void SysCatalog::createRole(const std::string& roleName,
2707  const bool user_private_role,
2708  const bool is_temporary) {
2710  &SysCatalog::createRole_unsafe, roleName, user_private_role, is_temporary);
2711 }
2712 
2713 void SysCatalog::dropRole(const std::string& roleName, const bool is_temporary) {
2714  execInTransaction(&SysCatalog::dropRole_unsafe, roleName, is_temporary);
2715 }
2716 
2717 void SysCatalog::grantRoleBatch(const std::vector<std::string>& roles,
2718  const std::vector<std::string>& grantees) {
2720 }
2721 
2722 void SysCatalog::grantRole(const std::string& role,
2723  const std::string& grantee,
2724  const bool is_temporary) {
2725  execInTransaction(&SysCatalog::grantRole_unsafe, role, grantee, is_temporary);
2726 }
2727 
2728 void SysCatalog::revokeRoleBatch(const std::vector<std::string>& roles,
2729  const std::vector<std::string>& grantees) {
2731 }
2732 
2733 void SysCatalog::revokeRole(const std::string& role,
2734  const std::string& grantee,
2735  const bool is_temporary) {
2736  execInTransaction(&SysCatalog::revokeRole_unsafe, role, grantee, is_temporary);
2737 }
2738 
2739 void SysCatalog::grantDBObjectPrivileges(const string& grantee,
2740  const DBObject& object,
2741  const Catalog_Namespace::Catalog& catalog) {
2743  &SysCatalog::grantDBObjectPrivileges_unsafe, grantee, object, catalog);
2744 }
2745 
2746 void SysCatalog::grantDBObjectPrivilegesBatch(const vector<string>& grantees,
2747  const vector<DBObject>& objects,
2748  const Catalog_Namespace::Catalog& catalog) {
2750  &SysCatalog::grantDBObjectPrivilegesBatch_unsafe, grantees, objects, catalog);
2751 }
2752 
2753 void SysCatalog::revokeDBObjectPrivileges(const string& grantee,
2754  const DBObject& object,
2755  const Catalog_Namespace::Catalog& catalog) {
2757  &SysCatalog::revokeDBObjectPrivileges_unsafe, grantee, object, catalog);
2758 }
2759 
2761  const vector<string>& grantees,
2762  const vector<DBObject>& objects,
2763  const Catalog_Namespace::Catalog& catalog) {
2765  &SysCatalog::revokeDBObjectPrivilegesBatch_unsafe, grantees, objects, catalog);
2766 }
2767 
2770 }
2771 
2773  Catalog* catalog) {
2776 }
2777 
2778 void SysCatalog::syncUserWithRemoteProvider(const std::string& user_name,
2779  std::vector<std::string> idp_roles,
2780  UserAlterations alts) {
2781  // need to escalate to a write lock
2782  // need to unlock the read lock
2783  sys_read_lock read_lock(this);
2784  read_lock.unlock();
2785  sys_write_lock write_lock(this);
2786  bool enable_idp_temporary_users{g_enable_idp_temporary_users && g_read_only};
2787  if (auto user = getUser(user_name); !user) {
2788  if (!alts.passwd) {
2789  alts.passwd = generate_random_string(72);
2790  }
2791  user = createUser(user_name, alts, /*is_temporary=*/enable_idp_temporary_users);
2792  LOG(INFO) << "Remote identity provider created user [" << user->userLoggable()
2793  << "] with (" << alts.toString() << ")";
2794  } else if (alts.wouldChange(*user)) {
2795  user = alterUser(user->userName, alts);
2796  LOG(INFO) << "Remote identity provider altered user [" << user->userLoggable()
2797  << "] with (" << alts.toString() << ")";
2798  }
2799  std::vector<std::string> current_roles = {};
2800  auto* user_rl = getUserGrantee(user_name);
2801  if (user_rl) {
2802  current_roles = user_rl->getRoles();
2803  }
2805  current_roles.begin(), current_roles.end(), current_roles.begin(), to_upper);
2806  std::transform(idp_roles.begin(), idp_roles.end(), idp_roles.begin(), to_upper);
2807  std::list<std::string> roles_revoked, roles_granted;
2808  // first remove obsolete ones
2809  for (auto& current_role_name : current_roles) {
2810  if (std::find(idp_roles.begin(), idp_roles.end(), current_role_name) ==
2811  idp_roles.end()) {
2812  revokeRole(current_role_name,
2813  user_name,
2814  /*is_temporary=*/enable_idp_temporary_users);
2815  roles_revoked.push_back(current_role_name);
2816  }
2817  }
2818  for (auto& role_name : idp_roles) {
2819  if (std::find(current_roles.begin(), current_roles.end(), role_name) ==
2820  current_roles.end()) {
2821  auto* rl = getRoleGrantee(role_name);
2822  if (rl) {
2823  grantRole(role_name,
2824  user_name,
2825  /*is_temporary=*/enable_idp_temporary_users);
2826  roles_granted.push_back(role_name);
2827  } else {
2828  LOG(WARNING) << "Error synchronizing roles for user " << user_name << ": role "
2829  << role_name << " does not exist";
2830  }
2831  }
2832  }
2833  if (roles_granted.empty() && roles_revoked.empty()) {
2834  LOG(INFO) << "Roles for user " << user_name
2835  << " are up to date with remote identity provider";
2836  } else {
2837  if (!roles_revoked.empty()) {
2838  LOG(INFO) << "Roles revoked during synchronization with identity provider for user "
2839  << user_name << ": " << join(roles_revoked, " ");
2840  }
2841  if (!roles_granted.empty()) {
2842  LOG(INFO) << "Roles granted during synchronization with identity provider for user "
2843  << user_name << ": " << join(roles_granted, " ");
2844  }
2845  }
2846 }
2847 
2848 std::unordered_map<std::string, std::vector<std::string>>
2849 SysCatalog::getGranteesOfSharedDashboards(const std::vector<std::string>& dashboard_ids) {
2850  sys_sqlite_lock sqlite_lock(this);
2851  std::unordered_map<std::string, std::vector<std::string>> active_grantees;
2852  sqliteConnector_->query("BEGIN TRANSACTION");
2853  try {
2854  for (auto dash : dashboard_ids) {
2855  std::vector<std::string> grantees = {};
2856  sqliteConnector_->query_with_text_params(
2857  "SELECT roleName FROM mapd_object_permissions WHERE objectPermissions NOT IN "
2858  "(0,1) AND objectPermissionsType = ? AND objectId = ?",
2859  std::vector<std::string>{
2860  std::to_string(static_cast<int32_t>(DashboardDBObjectType)), dash});
2861  int num_rows = sqliteConnector_->getNumRows();
2862  if (num_rows == 0) {
2863  // no grantees
2864  continue;
2865  } else {
2866  for (size_t i = 0; i < sqliteConnector_->getNumRows(); ++i) {
2867  grantees.push_back(sqliteConnector_->getData<string>(i, 0));
2868  }
2869  active_grantees[dash] = grantees;
2870  }
2871  }
2872  } catch (const std::exception& e) {
2873  sqliteConnector_->query("ROLLBACK TRANSACTION");
2874  throw;
2875  }
2876  sqliteConnector_->query("END TRANSACTION");
2877  return active_grantees;
2878 }
2879 
2880 std::shared_ptr<Catalog> SysCatalog::getCatalog(const std::string& dbName) {
2881  dbid_to_cat_map::const_accessor cata;
2882  if (cat_map_.find(cata, dbName)) {
2883  return cata->second;
2884  } else {
2886  if (getMetadataForDB(dbName, db_meta)) {
2887  return getCatalog(db_meta, false);
2888  } else {
2889  return nullptr;
2890  }
2891  }
2892 }
2893 
2894 std::shared_ptr<Catalog> SysCatalog::getCatalog(const int32_t db_id) {
2895  dbid_to_cat_map::const_accessor cata;
2896  for (dbid_to_cat_map::iterator cat_it = cat_map_.begin(); cat_it != cat_map_.end();
2897  ++cat_it) {
2898  if (cat_it->second->getDatabaseId() == db_id) {
2899  return cat_it->second;
2900  }
2901  }
2902  return nullptr;
2903 }
2904 
2905 std::shared_ptr<Catalog> SysCatalog::getCatalog(const DBMetadata& curDB, bool is_new_db) {
2906  {
2907  dbid_to_cat_map::const_accessor cata;
2908  if (cat_map_.find(cata, curDB.dbName)) {
2909  return cata->second;
2910  }
2911  }
2912 
2913  // Catalog doesnt exist
2914  // has to be made outside of lock as migration uses cat
2915  auto cat = std::make_shared<Catalog>(
2916  basePath_, curDB, dataMgr_, string_dict_hosts_, calciteMgr_, is_new_db);
2917 
2918  dbid_to_cat_map::accessor cata;
2919 
2920  if (cat_map_.find(cata, curDB.dbName)) {
2921  return cata->second;
2922  }
2923 
2924  cat_map_.insert(cata, curDB.dbName);
2925  cata->second = cat;
2926 
2927  return cat;
2928 }
2929 
2930 void SysCatalog::removeCatalog(const std::string& dbName) {
2931  cat_map_.erase(dbName);
2932 }
2933 
2935  const std::map<int32_t, std::vector<DBObject>>& old_owner_db_objects,
2936  int32_t new_owner_id,
2937  const Catalog_Namespace::Catalog& catalog) {
2938  sys_write_lock write_lock(this);
2939  sys_sqlite_lock sqlite_lock(this);
2940 
2941  sqliteConnector_->query("BEGIN TRANSACTION");
2942  try {
2943  UserMetadata new_owner;
2944  CHECK(getMetadataForUserById(new_owner_id, new_owner));
2945  for (const auto& [old_owner_id, db_objects] : old_owner_db_objects) {
2946  UserMetadata old_owner;
2947  CHECK(getMetadataForUserById(old_owner_id, old_owner));
2948  if (!old_owner.isSuper) {
2949  revokeDBObjectPrivilegesBatch_unsafe({old_owner.userName}, db_objects, catalog);
2950  }
2951  if (!new_owner.isSuper) {
2952  grantDBObjectPrivilegesBatch_unsafe({new_owner.userName}, db_objects, catalog);
2953  }
2954  }
2955 
2956  std::set<int32_t> old_owner_ids;
2957  for (const auto& [old_owner_id, db_objects] : old_owner_db_objects) {
2958  old_owner_ids.emplace(old_owner_id);
2959  }
2960 
2961  auto db_id = catalog.getDatabaseId();
2962  for (const auto old_user_id : old_owner_ids) {
2963  sqliteConnector_->query_with_text_params(
2964  "UPDATE mapd_object_permissions SET objectOwnerId = ? WHERE objectOwnerId = ? "
2965  "AND dbId = ? AND objectId != -1",
2966  std::vector<std::string>{std::to_string(new_owner_id),
2967  std::to_string(old_user_id),
2968  std::to_string(db_id)});
2969  }
2970 
2971  for (const auto& [user_or_role, grantee] : granteeMap_) {
2972  grantee->reassignObjectOwners(old_owner_ids, new_owner_id, db_id);
2973  }
2974 
2975  for (const auto& [object_key, object_descriptor] : objectDescriptorMap_) {
2976  if (object_descriptor->objectId != -1 && object_descriptor->dbId == db_id &&
2977  shared::contains(old_owner_ids, object_descriptor->objectOwnerId)) {
2978  object_descriptor->objectOwnerId = new_owner_id;
2979  }
2980  }
2981  } catch (std::exception& e) {
2982  sqliteConnector_->query("ROLLBACK TRANSACTION");
2984  throw;
2985  }
2986  sqliteConnector_->query("END TRANSACTION");
2987 }
2988 
2991  sys_write_lock write_lock(this);
2992  DBMetadata db_metadata;
2993  if (getMetadataForDB(shared::kInfoSchemaDbName, db_metadata)) {
2994  LOG(WARNING) << "A database with name \"" << shared::kInfoSchemaDbName
2995  << "\" already exists. System table creation will be skipped. Rename "
2996  "this database in order to use system tables.";
2997  } else {
2999  try {
3001  } catch (...) {
3003  dropDatabase(db_metadata);
3004  throw;
3005  }
3006  }
3007  }
3008 }
3009 
3010 bool SysCatalog::hasExecutedMigration(const std::string& migration_name) const {
3011  if (hasVersionHistoryTable()) {
3012  sys_sqlite_lock sqlite_lock(this);
3013  sqliteConnector_->query_with_text_params(
3014  "SELECT migration_history FROM mapd_version_history WHERE migration_history = ?",
3015  std::vector<std::string>{migration_name});
3016  return (sqliteConnector_->getNumRows() > 0);
3017  }
3018  return false;
3019 }
3020 
3021 void SysCatalog::recordExecutedMigration(const std::string& migration_name) const {
3022  if (!hasVersionHistoryTable()) {
3024  }
3025  sys_sqlite_lock sqlite_lock(this);
3026  sqliteConnector_->query_with_text_params(
3027  "INSERT INTO mapd_version_history(version, migration_history) values(?, ?)",
3028  std::vector<std::string>{std::to_string(MAPD_VERSION), migration_name});
3029 }
3030 
3032  sys_sqlite_lock sqlite_lock(this);
3033  sqliteConnector_->query(
3034  "select name from sqlite_master WHERE type='table' AND "
3035  "name='mapd_version_history'");
3036  return (sqliteConnector_->getNumRows() > 0);
3037 }
3038 
3040  sys_sqlite_lock sqlite_lock(this);
3041  sqliteConnector_->query(
3042  "CREATE TABLE mapd_version_history(version integer, migration_history text "
3043  "unique)");
3044 }
3045 
3047  // Rebuild updated maps from storage
3048  granteeMap_.clear();
3050  objectDescriptorMap_.clear();
3052 }
3053 
3054 } // namespace Catalog_Namespace
std::optional< std::string > passwd
Definition: SysCatalog.h:117
bool contains(const T &container, const U &element)
Definition: misc.h:195
static const AccessPrivileges VIEW_SQL_EDITOR
Definition: DBObject.h:152
auto get_users(SysCatalog &syscat, std::unique_ptr< SqliteConnector > &sqliteConnector, const int32_t dbId=-1)
void recordExecutedMigration(const std::string &migration_name) const
bool hasAnyPrivilegesOnDb(int32_t dbId, bool only_direct) const
Definition: Grantee.cpp:95
void revokeAllOnDatabase_unsafe(const std::string &roleName, int32_t dbId, Grantee *grantee)
const int kRootUserId
void revokeDBObjectPrivilegesBatch_unsafe(const std::vector< std::string > &grantees, const std::vector< DBObject > &objects, const Catalog_Namespace::Catalog &catalog)
std::vector< Catalog * > getCatalogsForAllDbs()
bool g_multi_instance
Definition: heavyai_locks.h:21
void dropUser(const std::string &name)
std::string cat(Ts &&...args)
DBObjectKey getObjectKey() const
Definition: DBObject.h:221
auto duplicateAndRenameCatalog(std::string const &current_name, std::string const &new_name)
Definition: SysCatalog.cpp:143
std::optional< std::string > default_db
Definition: SysCatalog.h:119
class for a per-database catalog. also includes metadata for the current database and the current use...
Definition: Catalog.h:132
void changeDBObjectOwnership(const UserMetadata &new_owner, const UserMetadata &previous_owner, DBObject object, const Catalog_Namespace::Catalog &catalog, bool revoke_privileges=true)
heavyai::shared_lock< heavyai::shared_mutex > read_lock
static const AccessPrivileges ALL_DATABASE
Definition: DBObject.h:151
virtual void grantPrivileges(const DBObject &object)
Definition: Grantee.cpp:105
DBObjectType
Definition: DBObject.h:40
std::set< std::string > getCreatedRoles() const
void grantRole(const std::string &role, const std::string &grantee, const bool is_temporary=false)
void updatePrivileges(const DBObject &object)
Definition: DBObject.cpp:152
void revokeRole(const std::string &role, const std::string &grantee, const bool is_temporary=false)
static const AccessPrivileges ALL_TABLE_MIGRATE
Definition: DBObject.h:156
#define LOG(tag)
Definition: Logger.h:216
bool checkPasswordForUser(const std::string &passwd, std::string &name, UserMetadata &user)
static const int32_t ALL
Definition: DBObject.h:77
void revokeDBObjectPrivileges_unsafe(const std::string &granteeName, DBObject object, const Catalog_Namespace::Catalog &catalog)
static void relaxMigrationLock()
std::optional< UserMetadata > getUser(std::string const &uname)
Definition: SysCatalog.h:197
void createRole_unsafe(const std::string &roleName, const bool userPrivateRole, const bool is_temporary)
void revokeDBObjectPrivilegesFromAll(DBObject object, Catalog *catalog)
bool getMetadataForUser(const std::string &name, UserMetadata &user)
void revokeDBObjectPrivileges(const std::string &grantee, const DBObject &object, const Catalog_Namespace::Catalog &catalog)
void removeCatalog(const std::string &dbName)
static bool parseUserMetadataFromSQLite(const std::unique_ptr< SqliteConnector > &conn, UserMetadata &user, int row)
std::string name() const
Definition: SysCatalog.h:350
std::string join(T const &container, std::string const &delim)
#define UNREACHABLE()
Definition: Logger.h:266
void createRole(const std::string &roleName, const bool user_private_role, const bool is_temporary=false)
const std::string kSystemCatalogName
void setObjectKey(const DBObjectKey &objectKey)
Definition: DBObject.h:225
ObjectRoleDescriptorMap objectDescriptorMap_
Definition: SysCatalog.h:483
Definition: Grantee.h:75
Grantee * getGrantee(const std::string &name) const
void dropDatabase(const DBMetadata &db)
void loginImpl(std::string &username, const std::string &password, UserMetadata &user_meta)
Definition: SysCatalog.cpp:888
int32_t objectId
Definition: DBObject.h:55
void setName(std::string name)
Definition: DBObject.h:218
Definition: Grantee.h:81
std::vector< ObjectRoleDescriptor > getMetadataForAllObjects() const
heavyai::unique_lock< heavyai::shared_mutex > write_lock
bool getMetadataForUserById(const int32_t idIn, UserMetadata &user)
void setPrivileges(const AccessPrivileges &privs)
Definition: DBObject.h:227
void insertOrUpdateObjectPrivileges(std::unique_ptr< SqliteConnector > &sqliteConnector, std::string roleName, bool userRole, const DBObject &object)
Definition: SysCatalog.cpp:476
const std::string kInfoSchemaDbName
void reassignObjectOwners(const std::map< int32_t, std::vector< DBObject >> &old_owner_db_objects, int32_t new_owner_id, const Catalog_Namespace::Catalog &catalog)
dsqliteMutex_(std::make_unique< heavyai::DistributedSharedMutex >(std::filesystem::path(basePath_)/shared::kLockfilesDirectoryName/shared::kCatalogDirectoryName/(currentDB_.dbName+".sqlite.lockfile")))
std::string toString(bool hide_password=true) const
std::optional< bool > is_super
Definition: SysCatalog.h:118
void createDBObject(const UserMetadata &user, const std::string &objectName, DBObjectType type, const Catalog_Namespace::Catalog &catalog, int32_t objectId=-1)
DBObject * findDbObject(const DBObjectKey &objectKey, bool only_direct) const
Definition: Grantee.cpp:85
constexpr double f
Definition: Utm.h:31
std::string to_string(char const *&&v)
void getDBObjectPrivileges(const std::string &granteeName, DBObject &object, const Catalog_Namespace::Catalog &catalog) const
void revokeRole_unsafe(const std::string &roleName, const std::string &granteeName, const bool is_temporary)
bool hasVersionHistoryTable() const
void grantDBObjectPrivileges_unsafe(const std::string &granteeName, const DBObject object, const Catalog_Namespace::Catalog &catalog)
static const AccessPrivileges ALL_VIEW
Definition: DBObject.h:177
void grantRoleBatch(const std::vector< std::string > &roles, const std::vector< std::string > &grantees)
std::unique_ptr< PkiServer > pki_server_
Definition: SysCatalog.h:487
void revokeDBObjectPrivilegesBatch(const std::vector< std::string > &grantees, const std::vector< DBObject > &objects, const Catalog_Namespace::Catalog &catalog)
void grantRoleBatch_unsafe(const std::vector< std::string > &roles, const std::vector< std::string > &grantees)
This file contains the class specification and related data structures for Catalog.
bool checkPrivileges(const UserMetadata &user, const std::vector< DBObject > &privObjects) const
void renameDBObject(const std::string &objectName, const std::string &newName, DBObjectType type, int32_t objectId, const Catalog_Namespace::Catalog &catalog)
static DBObjectKey fromString(const std::vector< std::string > &key, const DBObjectType &type)
Definition: DBObject.cpp:270
static SysCatalog & instance()
Definition: SysCatalog.h:337
This file contains the class specification and related data structures for SysCatalog.
bool g_enable_idp_temporary_users
Definition: SysCatalog.cpp:63
bool wouldChange(UserMetadata const &user_meta) const
Classes representing a parse tree.
void setPermissionType(const DBObjectType &permissionType)
Definition: DBObject.cpp:160
void getMetadataWithDefaultDB(std::string &dbname, const std::string &username, Catalog_Namespace::DBMetadata &db_meta, UserMetadata &user_meta)
const DBMetadata & getCurrentDB() const
Definition: Catalog.h:242
bool g_enable_system_tables
Definition: SysCatalog.cpp:64
const std::string kDefaultDbName
void grantAllOnDatabase_unsafe(const std::string &roleName, DBObject &object, const Catalog_Namespace::Catalog &catalog)
static const std::string getForeignTableSchema(bool if_not_exists=false)
Definition: Catalog.cpp:772
std::string g_base_path
Definition: SysCatalog.cpp:62
void init(LogOptions const &log_opts)
Definition: Logger.cpp:308
std::string generate_random_string(const size_t len)
DEVICE auto copy(ARGS &&...args)
Definition: gpu_enabled.h:51
#define CHECK_NE(x, y)
Definition: Logger.h:231
std::unordered_map< std::string, std::shared_ptr< UserMetadata > > temporary_users_by_name_
Definition: SysCatalog.h:512
virtual void revokeAllOnDatabase(int32_t dbId)
Definition: Grantee.cpp:296
std::string hash_with_bcrypt(const std::string &pwd)
Definition: SysCatalog.cpp:71
void renameObjectsInDescriptorMap(DBObject &object, const Catalog_Namespace::Catalog &cat)
bool checkPasswordForUserImpl(const std::string &passwd, std::string &name, UserMetadata &user)
static bool migrationEnabled()
Definition: MigrationMgr.h:43
std::shared_ptr< Catalog > login(std::string &db, std::string &username, const std::string &password, UserMetadata &user_meta, bool check_password=true)
Definition: SysCatalog.cpp:862
void revokeRoleBatch_unsafe(const std::vector< std::string > &roles, const std::vector< std::string > &grantees)
void grantRole_unsafe(const std::string &roleName, const std::string &granteeName, const bool is_temporary)
void revokeRoleBatch(const std::vector< std::string > &roles, const std::vector< std::string > &grantees)
std::shared_ptr< Data_Namespace::DataMgr > dataMgr_
Definition: SysCatalog.h:486
UserMetadata createUser(std::string const &name, UserAlterations alts, bool is_temporary)
Definition: SysCatalog.cpp:926
std::unique_lock< T > unique_lock
DBSummaryList getDatabaseListForUser(const UserMetadata &user)
static const int32_t MAPD_VERSION
Definition: release.h:32
static const AccessPrivileges ALL_DASHBOARD_MIGRATE
Definition: DBObject.h:168
std::shared_ptr< Catalog > switchDatabase(std::string &dbname, const std::string &username)
Definition: SysCatalog.cpp:896
Role * getRoleGrantee(const std::string &name) const
static const std::string getForeignServerSchema(bool if_not_exists=false)
Definition: Catalog.cpp:765
int getDatabaseId() const
Definition: Catalog.h:298
static const AccessPrivileges ALL_SERVER
Definition: DBObject.h:187
void revokeDBObjectPrivilegesFromAllBatch_unsafe(std::vector< DBObject > &objects, Catalog *catalog)
User * getUserGrantee(const std::string &name) const
void grantDBObjectPrivilegesBatch(const std::vector< std::string > &grantees, const std::vector< DBObject > &objects, const Catalog_Namespace::Catalog &catalog)
void grantDBObjectPrivileges(const std::string &grantee, const DBObject &object, const Catalog_Namespace::Catalog &catalog)
OUTPUT transform(INPUT const &input, FUNC const &func)
Definition: misc.h:296
std::unique_ptr< SqliteConnector > sqliteConnector_
Definition: SysCatalog.h:484
static const AccessPrivileges NONE
Definition: DBObject.h:148
void updateUserRoleName(const std::string &roleName, const std::string &newName)
std::list< UserMetadata > getAllUserMetadata()
void grantDBObjectPrivilegesBatch_unsafe(const std::vector< std::string > &grantees, const std::vector< DBObject > &objects, const Catalog_Namespace::Catalog &catalog)
static const std::string SYSTEM_ROLE_TAG("#dash_system_role")
specifies the content in-memory of a row in the dashboard
void execInTransaction(F &&f, Args &&...args)
void dropRole_unsafe(const std::string &roleName, const bool is_temporary)
std::string to_upper(const std::string &str)
void check_for_session_encryption(const std::string &pki_cert, std::string &session)
Definition: SysCatalog.cpp:918
void renameUser(std::string const &old_name, std::string const &new_name)
void loadKey()
Definition: DBObject.cpp:190
std::shared_ptr< Catalog > getCatalog(const std::string &dbName)
bool isRoleGrantedToGrantee(const std::string &granteeName, const std::string &roleName, bool only_direct) const
const std::string kRootUsername
void setObjectType(const DBObjectType &objectType)
Definition: DBObject.cpp:163
bool hasAnyPrivileges(const UserMetadata &user, std::vector< DBObject > &privObjects)
void deleteObjectDescriptorMap(const std::string &roleName)
static const AccessPrivileges ALL_VIEW_MIGRATE
Definition: DBObject.h:176
static void takeMigrationLock(const std::string &base_path)
bool g_read_only
Definition: File.cpp:40
void updateObjectDescriptorMap(const std::string &roleName, DBObject &object, bool roleType, const Catalog_Namespace::Catalog &cat)
std::unordered_map< int32_t, std::shared_ptr< UserMetadata > > temporary_users_by_id_
Definition: SysCatalog.h:513
void syncUserWithRemoteProvider(const std::string &user_name, std::vector< std::string > idp_roles, UserAlterations alts)
const std::string kDefaultRootPasswd
void dropRole(const std::string &roleName, const bool is_temporary=false)
void createVersionHistoryTable() const
std::list< DBMetadata > getAllDBMetadata()
static const std::string getCustomExpressionsSchema(bool if_not_exists=false)
Definition: Catalog.cpp:780
void renameDatabase(std::string const &old_name, std::string const &new_name)
int32_t dbId
Definition: DBObject.h:54
void revokeDBObjectPrivilegesFromAll_unsafe(DBObject object, Catalog *catalog)
const std::string kRootUserIdStr
static const AccessPrivileges ALL_DASHBOARD
Definition: DBObject.h:169
static const AccessPrivileges ACCESS
Definition: DBObject.h:153
bool verifyDBObjectOwnership(const UserMetadata &user, DBObject object, const Catalog_Namespace::Catalog &catalog)
static const AccessPrivileges ALL_TABLE
Definition: DBObject.h:157
const std::string kCatalogDirectoryName
std::vector< LeafHostInfo > string_dict_hosts_
Definition: SysCatalog.h:490
bool hasRole(Role *role, bool only_direct) const
Definition: Grantee.cpp:55
std::optional< bool > can_login
Definition: SysCatalog.h:120
#define CHECK(condition)
Definition: Logger.h:222
std::shared_ptr< Calcite > calciteMgr_
Definition: SysCatalog.h:489
std::unordered_map< std::string, std::vector< std::string > > getGranteesOfSharedDashboards(const std::vector< std::string > &dashboard_ids)
const std::string kLockfilesDirectoryName
std::list< DBSummary > DBSummaryList
Definition: SysCatalog.h:145
int32_t permissionType
Definition: DBObject.h:53
void populateRoleDbObjects(const std::vector< DBObject > &objects)
void deleteObjectPrivileges(std::unique_ptr< SqliteConnector > &sqliteConnector, std::string roleName, bool userRole, DBObject &object)
Definition: SysCatalog.cpp:457
int64_t privileges
Definition: DBObject.h:133
bool isDashboardSystemRole(const std::string &roleName) const
string name
Definition: setup.in.py:72
bool hasExecutedMigration(const std::string &migration_name) const
read_lock< SysCatalog > sys_read_lock
Definition: Catalog.cpp:122
bool g_enable_fsi
Definition: Catalog.cpp:96
std::string userLoggable() const
Definition: SysCatalog.cpp:127
bool getMetadataForDBById(const int32_t idIn, DBMetadata &db)
void createDatabase(const std::string &dbname, int owner)
UserMetadata alterUser(std::string const &name, UserAlterations alts)
void removeCatalogByFullPath(std::string const &full_path)
Definition: SysCatalog.cpp:135
DEVICE void swap(ARGS &&...args)
Definition: gpu_enabled.h:114
const std::string kInfoSchemaMigrationName
std::vector< ObjectRoleDescriptor * > getMetadataForObject(int32_t dbId, int32_t dbType, int32_t objectId) const
std::vector< std::string > getRoles(const std::string &user_name, bool effective=true)
virtual void renameDbObject(const DBObject &object)
Definition: Grantee.cpp:121
A selection of helper methods for File I/O.
#define VLOG(n)
Definition: Logger.h:316
std::filesystem::path copy_catalog_if_read_only(std::filesystem::path base_data_path)
Definition: SysCatalog.cpp:79
std::atomic< bool > isSuper
Definition: SysCatalog.h:107
bool getMetadataForDB(const std::string &name, DBMetadata &db)
void revokeDBObjectPrivilegesFromAllBatch(std::vector< DBObject > &objects, Catalog *catalog)