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