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