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