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