OmniSciDB  a575cb28ea
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros 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 <list>
30 #include <memory>
31 #include <random>
32 #include <sstream>
33 #include <string_view>
34 #include "Catalog.h"
35 
36 #include "Catalog/AuthMetadata.h"
38 
39 #include <boost/algorithm/string/predicate.hpp>
40 #include <boost/filesystem.hpp>
41 #include <boost/range/adaptor/map.hpp>
42 #include <boost/version.hpp>
43 
44 #include "../Parser/ParserNode.h"
45 #include "../Shared/File.h"
46 #include "../Shared/StringTransform.h"
47 #include "../Shared/measure.h"
48 #include "MapDRelease.h"
49 #include "RWLocks.h"
50 #include "bcrypt.h"
51 
52 using std::list;
53 using std::map;
54 using std::pair;
55 using std::runtime_error;
56 using std::string;
57 using std::vector;
58 
59 using namespace std::string_literals;
60 
61 extern bool g_enable_fsi;
62 extern bool g_enable_s3_fsi;
63 
64 namespace {
65 
66 std::string hash_with_bcrypt(const std::string& pwd) {
67  char salt[BCRYPT_HASHSIZE], hash[BCRYPT_HASHSIZE];
68  CHECK(bcrypt_gensalt(-1, salt) == 0);
69  CHECK(bcrypt_hashpw(pwd.c_str(), salt, hash) == 0);
70  return std::string(hash, BCRYPT_HASHSIZE);
71 }
72 
73 } // namespace
74 
75 namespace Catalog_Namespace {
76 
77 thread_local bool SysCatalog::thread_holds_read_lock = false;
78 
79 using sys_read_lock = read_lock<SysCatalog>;
82 
83 bool g_log_user_id{false}; // --log-user-id
84 
85 std::string UserMetadata::userLoggable() const {
86  return g_log_user_id ? std::to_string(userId) : userName;
87 }
88 
89 auto CommonFileOperations::assembleCatalogName(std::string const& name) {
90  return base_path_ + "/mapd_catalogs/" + name;
91 };
92 
93 void CommonFileOperations::removeCatalogByFullPath(std::string const& full_path) {
94  boost::filesystem::remove(full_path);
95 }
96 
97 void CommonFileOperations::removeCatalogByName(std::string const& name) {
98  boost::filesystem::remove(assembleCatalogName(name));
99 };
100 
101 auto CommonFileOperations::duplicateAndRenameCatalog(std::string const& current_name,
102  std::string const& new_name) {
103  auto full_current_path = assembleCatalogName(current_name);
104  auto full_new_path = assembleCatalogName(new_name);
105 
106  try {
107  boost::filesystem::copy_file(full_current_path, full_new_path);
108  } catch (std::exception& e) {
109  std::string err_message{"Could not copy file " + full_current_path + " to " +
110  full_new_path + " exception was " + e.what()};
111  LOG(ERROR) << err_message;
112  throw std::runtime_error(err_message);
113  }
114 
115  return std::make_pair(full_current_path, full_new_path);
116 };
117 
118 void SysCatalog::init(const std::string& basePath,
119  std::shared_ptr<Data_Namespace::DataMgr> dataMgr,
120  const AuthMetadata& authMetadata,
121  std::shared_ptr<Calcite> calcite,
122  bool is_new_db,
123  bool aggregator,
124  const std::vector<LeafHostInfo>& string_dict_hosts) {
125  {
128 
129  basePath_ = basePath;
130  dataMgr_ = dataMgr;
131  authMetadata_ = &authMetadata;
132  pki_server_.reset(new PkiServer(*authMetadata_));
133  calciteMgr_ = calcite;
134  string_dict_hosts_ = string_dict_hosts;
135  aggregator_ = aggregator;
136  bool db_exists =
137  boost::filesystem::exists(basePath_ + "/mapd_catalogs/" + OMNISCI_SYSTEM_CATALOG);
138  sqliteConnector_.reset(
139  new SqliteConnector(OMNISCI_SYSTEM_CATALOG, basePath_ + "/mapd_catalogs/"));
140  if (is_new_db) {
141  initDB();
142  } else {
143  if (!db_exists) {
144  importDataFromOldMapdDB();
145  }
146  checkAndExecuteMigrations();
147  }
148  buildRoleMap();
149  buildUserRoleMap();
150  buildObjectDescriptorMap();
151  }
152 }
153 
154 SysCatalog::~SysCatalog() {
156  for (auto grantee = granteeMap_.begin(); grantee != granteeMap_.end(); ++grantee) {
157  delete grantee->second;
158  }
159  granteeMap_.clear();
160  for (ObjectRoleDescriptorMap::iterator objectIt = objectDescriptorMap_.begin();
161  objectIt != objectDescriptorMap_.end();) {
162  ObjectRoleDescriptorMap::iterator eraseIt = objectIt++;
163  delete eraseIt->second;
164  }
165  objectDescriptorMap_.clear();
166 
167  cat_map_.clear();
168 }
169 
170 void SysCatalog::initDB() {
172  sqliteConnector_->query("BEGIN TRANSACTION");
173  try {
174  sqliteConnector_->query(
175  "CREATE TABLE mapd_users (userid integer primary key, name text unique, "
176  "passwd_hash text, issuper boolean, default_db integer references "
177  "mapd_databases, can_login boolean)");
178  sqliteConnector_->query_with_text_params(
179  "INSERT INTO mapd_users VALUES (?, ?, ?, 1, NULL, 1)",
180  std::vector<std::string>{OMNISCI_ROOT_USER_ID_STR,
183  sqliteConnector_->query(
184  "CREATE TABLE mapd_databases (dbid integer primary key, name text unique, owner "
185  "integer references mapd_users)");
186  sqliteConnector_->query(
187  "CREATE TABLE mapd_roles(roleName text, userName text, UNIQUE(roleName, "
188  "userName))");
189  sqliteConnector_->query(
190  "CREATE TABLE mapd_object_permissions ("
191  "roleName text, "
192  "roleType bool, "
193  "dbId integer references mapd_databases, "
194  "objectName text, "
195  "objectId integer, "
196  "objectPermissionsType integer, "
197  "objectPermissions integer, "
198  "objectOwnerId integer, UNIQUE(roleName, objectPermissionsType, dbId, "
199  "objectId))");
200  } catch (const std::exception&) {
201  sqliteConnector_->query("ROLLBACK TRANSACTION");
202  throw;
203  }
204  sqliteConnector_->query("END TRANSACTION");
205  createDatabase(OMNISCI_DEFAULT_DB, OMNISCI_ROOT_USER_ID);
206  createRole_unsafe(OMNISCI_ROOT_USER, true);
207 }
208 
209 void SysCatalog::checkAndExecuteMigrations() {
210  migratePrivileged_old();
211  createUserRoles();
212  migratePrivileges();
213  migrateDBAccessPrivileges();
214  updateUserSchema(); // must come before updatePasswordsToHashes()
215  updatePasswordsToHashes();
216  updateBlankPasswordsToRandom(); // must come after updatePasswordsToHashes()
217  updateSupportUserDeactivation();
218  addAdminUserRole();
219 }
220 
221 void SysCatalog::updateUserSchema() {
223 
224  // check to see if the new column already exists
225  sqliteConnector_->query("PRAGMA TABLE_INFO(mapd_users)");
226  for (size_t i = 0; i < sqliteConnector_->getNumRows(); i++) {
227  const auto& col_name = sqliteConnector_->getData<std::string>(i, 1);
228  if (col_name == "default_db") {
229  return; // new column already exists
230  }
231  }
232 
233  // create the new column
234  sqliteConnector_->query("BEGIN TRANSACTION");
235  try {
236  sqliteConnector_->query(
237  "ALTER TABLE mapd_users ADD COLUMN default_db INTEGER REFERENCES mapd_databases");
238  } catch (const std::exception& e) {
239  sqliteConnector_->query("ROLLBACK TRANSACTION");
240  throw;
241  }
242  sqliteConnector_->query("END TRANSACTION");
243 }
244 
245 void SysCatalog::importDataFromOldMapdDB() {
247  std::string mapd_db_path = basePath_ + "/mapd_catalogs/mapd";
248  sqliteConnector_->query("ATTACH DATABASE `" + mapd_db_path + "` as old_cat");
249  sqliteConnector_->query("BEGIN TRANSACTION");
250  LOG(INFO) << "Moving global metadata into a separate catalog";
251  try {
252  auto moveTableIfExists = [conn = sqliteConnector_.get()](const std::string& tableName,
253  bool deleteOld = true) {
254  conn->query("SELECT sql FROM old_cat.sqlite_master WHERE type='table' AND name='" +
255  tableName + "'");
256  if (conn->getNumRows() != 0) {
257  conn->query(conn->getData<string>(0, 0));
258  conn->query("INSERT INTO " + tableName + " SELECT * FROM old_cat." + tableName);
259  if (deleteOld) {
260  conn->query("DROP TABLE old_cat." + tableName);
261  }
262  }
263  };
264  moveTableIfExists("mapd_users");
265  moveTableIfExists("mapd_databases");
266  moveTableIfExists("mapd_roles");
267  moveTableIfExists("mapd_object_permissions");
268  moveTableIfExists("mapd_privileges");
269  moveTableIfExists("mapd_version_history", false);
270  } catch (const std::exception& e) {
271  LOG(ERROR) << "Failed to move global metadata into a separate catalog: " << e.what();
272  sqliteConnector_->query("ROLLBACK TRANSACTION");
273  try {
274  sqliteConnector_->query("DETACH DATABASE old_cat");
275  } catch (const std::exception&) {
276  // nothing to do here
277  }
278  throw;
279  }
280  sqliteConnector_->query("END TRANSACTION");
281  const std::string sys_catalog_path =
282  basePath_ + "/mapd_catalogs/" + OMNISCI_SYSTEM_CATALOG;
283  LOG(INFO) << "Global metadata has been successfully moved into a separate catalog: "
284  << sys_catalog_path
285  << ". Using this database with an older version of omnisci_server "
286  "is now impossible.";
287  try {
288  sqliteConnector_->query("DETACH DATABASE old_cat");
289  } catch (const std::exception&) {
290  // nothing to do here
291  }
292 }
293 
294 void SysCatalog::createUserRoles() {
296  sqliteConnector_->query("BEGIN TRANSACTION");
297  try {
298  sqliteConnector_->query(
299  "SELECT name FROM sqlite_master WHERE type='table' AND name='mapd_roles'");
300  if (sqliteConnector_->getNumRows() != 0) {
301  // already done
302  sqliteConnector_->query("END TRANSACTION");
303  return;
304  }
305  sqliteConnector_->query(
306  "CREATE TABLE mapd_roles(roleName text, userName text, UNIQUE(roleName, "
307  "userName))");
308  // need to account for old conversions where we are building and moving
309  // from pre version 4.0 and 'mapd' was default superuser
310  sqliteConnector_->query("SELECT name FROM mapd_users WHERE name NOT IN ( \'" +
311  OMNISCI_ROOT_USER + "\', 'mapd')");
312  size_t numRows = sqliteConnector_->getNumRows();
313  vector<string> user_names;
314  for (size_t i = 0; i < numRows; ++i) {
315  user_names.push_back(sqliteConnector_->getData<string>(i, 0));
316  }
317  for (const auto& user_name : user_names) {
318  // for each user, create a fake role with the same name
319  sqliteConnector_->query_with_text_params(
320  "INSERT INTO mapd_roles(roleName, userName) VALUES (?, ?)",
321  vector<string>{user_name, user_name});
322  }
323  } catch (const std::exception&) {
324  sqliteConnector_->query("ROLLBACK TRANSACTION");
325  throw;
326  }
327  sqliteConnector_->query("END TRANSACTION");
328 }
329 
330 namespace {
331 
332 void deleteObjectPrivileges(std::unique_ptr<SqliteConnector>& sqliteConnector,
333  std::string roleName,
334  bool userRole,
335  DBObject& object) {
336  DBObjectKey key = object.getObjectKey();
337 
338  sqliteConnector->query_with_text_params(
339  "DELETE FROM mapd_object_permissions WHERE roleName = ?1 and roleType = ?2 and "
340  "objectPermissionsType = ?3 and "
341  "dbId = "
342  "?4 "
343  "and objectId = ?5",
344  std::vector<std::string>{roleName,
345  std::to_string(userRole),
347  std::to_string(key.dbId),
348  std::to_string(key.objectId)});
349 }
350 
351 void insertOrUpdateObjectPrivileges(std::unique_ptr<SqliteConnector>& sqliteConnector,
352  std::string roleName,
353  bool userRole,
354  DBObject& object) {
355  CHECK(object.valid());
356  DBObjectKey key = object.getObjectKey();
357 
358  sqliteConnector->query_with_text_params(
359  "INSERT OR REPLACE INTO mapd_object_permissions("
360  "roleName, "
361  "roleType, "
362  "objectPermissionsType, "
363  "dbId, "
364  "objectId, "
365  "objectPermissions, "
366  "objectOwnerId,"
367  "objectName) "
368  "VALUES (?1, ?2, ?3, "
369  "?4, ?5, ?6, ?7, ?8)",
370  std::vector<std::string>{
371  roleName, // roleName
372  userRole ? "1" : "0", // roleType
373  std::to_string(key.permissionType), // permissionType
374  std::to_string(key.dbId), // dbId
375  std::to_string(key.objectId), // objectId
376  std::to_string(object.getPrivileges().privileges), // objectPrivileges
377  std::to_string(object.getOwner()), // objectOwnerId
378  object.getName() // name
379  });
380 }
381 
382 } // namespace
383 
384 void SysCatalog::migratePrivileges() {
386  sqliteConnector_->query("BEGIN TRANSACTION");
387  try {
388  sqliteConnector_->query(
389  "SELECT name FROM sqlite_master WHERE type='table' AND "
390  "name='mapd_object_permissions'");
391  if (sqliteConnector_->getNumRows() != 0) {
392  // already done
393  sqliteConnector_->query("END TRANSACTION");
394  return;
395  }
396 
397  sqliteConnector_->query(
398  "CREATE TABLE IF NOT EXISTS mapd_object_permissions ("
399  "roleName text, "
400  "roleType bool, "
401  "dbId integer references mapd_databases, "
402  "objectName text, "
403  "objectId integer, "
404  "objectPermissionsType integer, "
405  "objectPermissions integer, "
406  "objectOwnerId integer, UNIQUE(roleName, objectPermissionsType, dbId, "
407  "objectId))");
408 
409  // get the list of databases and their grantees
410  sqliteConnector_->query(
411  "SELECT userid, dbid FROM mapd_privileges WHERE select_priv = 1 and insert_priv "
412  "= 1");
413  size_t numRows = sqliteConnector_->getNumRows();
414  vector<pair<int, int>> db_grantees(numRows);
415  for (size_t i = 0; i < numRows; ++i) {
416  db_grantees[i].first = sqliteConnector_->getData<int>(i, 0);
417  db_grantees[i].second = sqliteConnector_->getData<int>(i, 1);
418  }
419  // map user names to user ids
420  sqliteConnector_->query("select userid, name from mapd_users");
421  numRows = sqliteConnector_->getNumRows();
422  std::unordered_map<int, string> users_by_id;
423  std::unordered_map<int, bool> user_has_privs;
424  for (size_t i = 0; i < numRows; ++i) {
425  users_by_id[sqliteConnector_->getData<int>(i, 0)] =
426  sqliteConnector_->getData<string>(i, 1);
427  user_has_privs[sqliteConnector_->getData<int>(i, 0)] = false;
428  }
429  // map db names to db ids
430  sqliteConnector_->query("select dbid, name from mapd_databases");
431  numRows = sqliteConnector_->getNumRows();
432  std::unordered_map<int, string> dbs_by_id;
433  for (size_t i = 0; i < numRows; ++i) {
434  dbs_by_id[sqliteConnector_->getData<int>(i, 0)] =
435  sqliteConnector_->getData<string>(i, 1);
436  }
437  // migrate old privileges to new privileges: if user had insert access to database, he
438  // was a grantee
439  for (const auto& grantee : db_grantees) {
440  user_has_privs[grantee.first] = true;
441  auto dbName = dbs_by_id[grantee.second];
442  {
443  // table level permissions
444  DBObjectKey key;
446  key.dbId = grantee.second;
448  object.setName(dbName);
450  sqliteConnector_, users_by_id[grantee.first], true, object);
451  }
452 
453  {
454  // dashboard level permissions
455  DBObjectKey key;
457  key.dbId = grantee.second;
458  DBObject object(
460  object.setName(dbName);
462  sqliteConnector_, users_by_id[grantee.first], true, object);
463  }
464 
465  {
466  // view level permissions
467  DBObjectKey key;
469  key.dbId = grantee.second;
471  object.setName(dbName);
473  sqliteConnector_, users_by_id[grantee.first], true, object);
474  }
475  }
476  for (auto user : user_has_privs) {
477  auto dbName = dbs_by_id[0];
478  if (user.second == false && user.first != OMNISCI_ROOT_USER_ID) {
479  {
480  DBObjectKey key;
482  key.dbId = 0;
484  object.setName(dbName);
486  sqliteConnector_, users_by_id[user.first], true, object);
487  }
488  }
489  }
490  } catch (const std::exception&) {
491  sqliteConnector_->query("ROLLBACK TRANSACTION");
492  throw;
493  }
494  sqliteConnector_->query("END TRANSACTION");
495 }
496 
497 void SysCatalog::addAdminUserRole() {
499  sqliteConnector_->query("BEGIN TRANSACTION");
500  try {
501  sqliteConnector_->query(
502  "SELECT roleName FROM mapd_object_permissions WHERE roleName = \'" +
503  OMNISCI_ROOT_USER + "\'");
504  if (sqliteConnector_->getNumRows() != 0) {
505  // already done
506  sqliteConnector_->query("END TRANSACTION");
507  return;
508  }
509 
510  createRole_unsafe(OMNISCI_ROOT_USER, true);
511  } catch (const std::exception&) {
512  sqliteConnector_->query("ROLLBACK TRANSACTION");
513  throw;
514  }
515  sqliteConnector_->query("END TRANSACTION");
516 }
517 
518 void SysCatalog::updatePasswordsToHashes() {
520  sqliteConnector_->query("BEGIN TRANSACTION");
521  try {
522  sqliteConnector_->query(
523  "SELECT name FROM sqlite_master WHERE type='table' AND name='mapd_users'");
524  if (sqliteConnector_->getNumRows() == 0) {
525  // Nothing to update
526  sqliteConnector_->query("END TRANSACTION");
527  return;
528  }
529  sqliteConnector_->query("PRAGMA TABLE_INFO(mapd_users)");
530  for (size_t i = 0; i < sqliteConnector_->getNumRows(); i++) {
531  const auto& col_name = sqliteConnector_->getData<std::string>(i, 1);
532  if (col_name == "passwd_hash") {
533  sqliteConnector_->query("END TRANSACTION");
534  return;
535  }
536  }
537  // Alas, SQLite can't drop columns so we have to recreate the table
538  // (or, optionally, add the new column and reset the old one to a bunch of nulls)
539  sqliteConnector_->query("SELECT userid, passwd FROM mapd_users");
540  auto numRows = sqliteConnector_->getNumRows();
541  vector<std::string> users, passwords;
542  for (size_t i = 0; i < numRows; i++) {
543  users.push_back(sqliteConnector_->getData<std::string>(i, 0));
544  passwords.push_back(sqliteConnector_->getData<std::string>(i, 1));
545  }
546  sqliteConnector_->query(
547  "CREATE TABLE mapd_users_tmp (userid integer primary key, name text unique, "
548  "passwd_hash text, issuper boolean, default_db integer references "
549  "mapd_databases)");
550  sqliteConnector_->query(
551  "INSERT INTO mapd_users_tmp(userid, name, passwd_hash, issuper, default_db) "
552  "SELECT userid, name, null, issuper, default_db FROM mapd_users");
553  for (size_t i = 0; i < users.size(); ++i) {
554  sqliteConnector_->query_with_text_params(
555  "UPDATE mapd_users_tmp SET passwd_hash = ? WHERE userid = ?",
556  std::vector<std::string>{hash_with_bcrypt(passwords[i]), users[i]});
557  }
558  sqliteConnector_->query("DROP TABLE mapd_users");
559  sqliteConnector_->query("ALTER TABLE mapd_users_tmp RENAME TO mapd_users");
560  } catch (const std::exception& e) {
561  LOG(ERROR) << "Failed to hash passwords: " << e.what();
562  sqliteConnector_->query("ROLLBACK TRANSACTION");
563  throw;
564  }
565  sqliteConnector_->query("END TRANSACTION");
566  sqliteConnector_->query("VACUUM"); // physically delete plain text passwords
567  LOG(INFO) << "Passwords were successfully hashed";
568 }
569 
570 void SysCatalog::updateBlankPasswordsToRandom() {
571  const std::string UPDATE_BLANK_PASSWORDS_TO_RANDOM = "update_blank_passwords_to_random";
572  sqliteConnector_->query_with_text_params(
573  "SELECT migration_history FROM mapd_version_history WHERE migration_history = ?",
574  std::vector<std::string>{UPDATE_BLANK_PASSWORDS_TO_RANDOM});
575  if (sqliteConnector_->getNumRows()) {
576  return;
577  }
578 
580  sqliteConnector_->query("BEGIN TRANSACTION");
581  try {
582  sqliteConnector_->query(
583  "SELECT userid, passwd_hash, name FROM mapd_users WHERE name <> 'mapd'");
584  auto numRows = sqliteConnector_->getNumRows();
585  vector<std::string> users, passwords, names;
586  for (size_t i = 0; i < numRows; i++) {
587  users.push_back(sqliteConnector_->getData<std::string>(i, 0));
588  passwords.push_back(sqliteConnector_->getData<std::string>(i, 1));
589  names.push_back(sqliteConnector_->getData<std::string>(i, 2));
590  }
591  for (size_t i = 0; i < users.size(); ++i) {
592  int pwd_check_result = bcrypt_checkpw("", passwords[i].c_str());
593  // if the check fails there is a good chance that data on disc is broken
594  CHECK(pwd_check_result >= 0);
595  if (pwd_check_result != 0) {
596  continue;
597  }
598  LOG(WARNING) << "resetting blank password for user " << names[i] << " (" << users[i]
599  << ") to a random password";
600  sqliteConnector_->query_with_text_params(
601  "UPDATE mapd_users SET passwd_hash = ? WHERE userid = ?",
602  std::vector<std::string>{hash_with_bcrypt(generate_random_string(72)),
603  users[i]});
604  }
605  sqliteConnector_->query_with_text_params(
606  "INSERT INTO mapd_version_history(version, migration_history) values(?,?)",
607  std::vector<std::string>{std::to_string(MAPD_VERSION),
608  UPDATE_BLANK_PASSWORDS_TO_RANDOM});
609  } catch (const std::exception& e) {
610  LOG(ERROR) << "Failed to fix blank passwords: " << e.what();
611  sqliteConnector_->query("ROLLBACK TRANSACTION");
612  throw;
613  }
614  sqliteConnector_->query("END TRANSACTION");
615 }
616 
617 void SysCatalog::updateSupportUserDeactivation() {
618  const std::string UPDATE_SUPPORT_USER_DEACTIVATION = "update_support_user_deactivation";
620  // check to see if the new column already exists
621  sqliteConnector_->query("PRAGMA TABLE_INFO(mapd_users)");
622  for (size_t i = 0; i < sqliteConnector_->getNumRows(); i++) {
623  const auto& col_name = sqliteConnector_->getData<std::string>(i, 1);
624  if (col_name == "can_login") {
625  return; // new column already exists
626  }
627  }
628  sqliteConnector_->query("BEGIN TRANSACTION");
629  try {
630  sqliteConnector_->query("ALTER TABLE mapd_users ADD COLUMN can_login BOOLEAN");
631  sqliteConnector_->query("UPDATE mapd_users SET can_login = true");
632  sqliteConnector_->query_with_text_params(
633  "INSERT INTO mapd_version_history(version, migration_history) values(?,?)",
634  std::vector<std::string>{std::to_string(MAPD_VERSION),
635  UPDATE_SUPPORT_USER_DEACTIVATION});
636  } catch (const std::exception& e) {
637  LOG(ERROR) << "Failed to add support for user deactivation: " << e.what();
638  sqliteConnector_->query("ROLLBACK TRANSACTION");
639  throw;
640  }
641  sqliteConnector_->query("END TRANSACTION");
642 }
643 
644 void SysCatalog::migrateDBAccessPrivileges() {
646  sqliteConnector_->query("BEGIN TRANSACTION");
647  try {
648  sqliteConnector_->query(
649  "select name from sqlite_master WHERE type='table' AND "
650  "name='mapd_version_history'");
651  if (sqliteConnector_->getNumRows() == 0) {
652  sqliteConnector_->query(
653  "CREATE TABLE mapd_version_history(version integer, migration_history text "
654  "unique)");
655  } else {
656  sqliteConnector_->query(
657  "select * from mapd_version_history where migration_history = "
658  "'db_access_privileges'");
659  if (sqliteConnector_->getNumRows() != 0) {
660  // both privileges migrated
661  // no need for further execution
662  sqliteConnector_->query("END TRANSACTION");
663  return;
664  }
665  }
666  // Insert check for migration
667  sqliteConnector_->query_with_text_params(
668  "INSERT INTO mapd_version_history(version, migration_history) values(?,?)",
669  std::vector<std::string>{std::to_string(MAPD_VERSION), "db_access_privileges"});
670 
671  sqliteConnector_->query("select dbid, name from mapd_databases");
672  std::unordered_map<int, string> databases;
673  for (size_t i = 0; i < sqliteConnector_->getNumRows(); ++i) {
674  databases[sqliteConnector_->getData<int>(i, 0)] =
675  sqliteConnector_->getData<string>(i, 1);
676  }
677 
678  sqliteConnector_->query("select userid, name from mapd_users");
679  std::unordered_map<int, string> users;
680  for (size_t i = 0; i < sqliteConnector_->getNumRows(); ++i) {
681  users[sqliteConnector_->getData<int>(i, 0)] =
682  sqliteConnector_->getData<string>(i, 1);
683  }
684 
685  // All existing users by default will be granted DB Access permissions
686  // and view sql editor privileges
687  DBMetadata dbmeta;
688  for (auto db_ : databases) {
689  CHECK(SysCatalog::instance().getMetadataForDB(db_.second, dbmeta));
690  for (auto user : users) {
691  if (user.first != OMNISCI_ROOT_USER_ID) {
692  {
693  DBObjectKey key;
695  key.dbId = dbmeta.dbId;
696 
697  // access permission;
698  DBObject object_access(key, AccessPrivileges::ACCESS, dbmeta.dbOwner);
700  object_access.setName(dbmeta.dbName);
701  // sql_editor permission
702  DBObject object_editor(
705  object_editor.setName(dbmeta.dbName);
706  object_editor.updatePrivileges(object_access);
708  sqliteConnector_, user.second, true, object_editor);
709  }
710  }
711  }
712  }
713  } catch (const std::exception& e) {
714  LOG(ERROR) << "Failed to migrate db access privileges: " << e.what();
715  sqliteConnector_->query("ROLLBACK TRANSACTION");
716  throw;
717  }
718  sqliteConnector_->query("END TRANSACTION");
719  LOG(INFO) << "Successfully migrated db access privileges";
720 }
721 
722 void SysCatalog::migratePrivileged_old() {
724 
725  sqliteConnector_->query("BEGIN TRANSACTION");
726  try {
727  sqliteConnector_->query(
728  "CREATE TABLE IF NOT EXISTS mapd_privileges (userid integer references "
729  "mapd_users, dbid integer references "
730  "mapd_databases, select_priv boolean, insert_priv boolean, UNIQUE(userid, "
731  "dbid))");
732  } catch (const std::exception& e) {
733  sqliteConnector_->query("ROLLBACK TRANSACTION");
734  throw;
735  }
736  sqliteConnector_->query("END TRANSACTION");
737 }
738 
739 std::shared_ptr<Catalog> SysCatalog::login(std::string& dbname,
740  std::string& username,
741  const std::string& password,
742  UserMetadata& user_meta,
743  bool check_password) {
744  // NOTE(sy): The dbname isn't const because getMetadataWithDefaultDB()
745  // can reset it. The username isn't const because SamlServer's
746  // login()/authenticate_user() can reset it.
747 
748  if (check_password) {
749  loginImpl(username, password, user_meta);
750  } else { // not checking for password so user must exist
751  if (!getMetadataForUser(username, user_meta)) {
752  throw std::runtime_error("Invalid credentials.");
753  }
754  }
755  // we should have a user and user_meta by now
756  if (!user_meta.can_login) {
757  throw std::runtime_error("Unauthorized Access: User " + username + " is deactivated");
758  }
760  getMetadataWithDefaultDB(dbname, username, db_meta, user_meta);
761  return getCatalog(basePath_, db_meta, dataMgr_, string_dict_hosts_, calciteMgr_, false);
762 }
763 
764 // loginImpl() with no EE code and no SAML code
765 void SysCatalog::loginImpl(std::string& username,
766  const std::string& password,
767  UserMetadata& user_meta) {
768  if (!checkPasswordForUser(password, username, user_meta)) {
769  throw std::runtime_error("Authentication failure");
770  }
771 }
772 
773 std::shared_ptr<Catalog> SysCatalog::switchDatabase(std::string& dbname,
774  const std::string& username) {
775  DBMetadata db_meta;
776  UserMetadata user_meta;
777 
778  getMetadataWithDefaultDB(dbname, username, db_meta, user_meta);
779 
780  // NOTE(max): register database in Catalog that early to allow ldap
781  // and saml create default user and role privileges on databases
782  auto cat =
783  getCatalog(basePath_, db_meta, dataMgr_, string_dict_hosts_, calciteMgr_, false);
784 
785  DBObject dbObject(dbname, DatabaseDBObjectType);
786  dbObject.loadKey();
788  if (!checkPrivileges(user_meta, std::vector<DBObject>{dbObject})) {
789  throw std::runtime_error("Unauthorized Access: user " + user_meta.userLoggable() +
790  " is not allowed to access database " + dbname + ".");
791  }
792 
793  return cat;
794 }
795 
796 void SysCatalog::check_for_session_encryption(const std::string& pki_cert,
797  std::string& session) {
798  if (!pki_server_->inUse()) {
799  return;
800  }
801  pki_server_->encrypt_session(pki_cert, session);
802 }
803 
804 void SysCatalog::createUser(const string& name,
805  const string& passwd,
806  bool issuper,
807  const std::string& dbname,
808  bool can_login) {
811 
812  UserMetadata user;
813  if (getMetadataForUser(name, user)) {
814  throw runtime_error("User " + user.userLoggable() + " already exists.");
815  }
816  if (getGrantee(name)) {
817  std::string const loggable = g_log_user_id ? std::string("") : name + ' ';
818  throw runtime_error(
819  "User " + loggable +
820  "is same as one of existing grantees. User and role names should be unique.");
821  }
822  sqliteConnector_->query("BEGIN TRANSACTION");
823  try {
824  std::vector<std::string> vals;
825  if (!dbname.empty()) {
826  DBMetadata db;
827  if (!SysCatalog::instance().getMetadataForDB(dbname, db)) {
828  throw runtime_error("DEFAULT_DB " + dbname + " not found.");
829  }
830  vals = {name,
831  hash_with_bcrypt(passwd),
832  std::to_string(issuper),
833  std::to_string(db.dbId),
834  std::to_string(can_login)};
835  sqliteConnector_->query_with_text_params(
836  "INSERT INTO mapd_users (name, passwd_hash, issuper, default_db, can_login) "
837  "VALUES (?, ?, ?, ?, ?)",
838  vals);
839  } else {
840  vals = {name,
841  hash_with_bcrypt(passwd),
842  std::to_string(issuper),
843  std::to_string(can_login)};
844  sqliteConnector_->query_with_text_params(
845  "INSERT INTO mapd_users (name, passwd_hash, issuper, can_login) "
846  "VALUES (?, ?, ?, ?)",
847  vals);
848  }
849  createRole_unsafe(name, true);
850  } catch (const std::exception& e) {
851  sqliteConnector_->query("ROLLBACK TRANSACTION");
852  throw;
853  }
854  sqliteConnector_->query("END TRANSACTION");
855 }
856 
857 void SysCatalog::dropUser(const string& name) {
860 
861  sqliteConnector_->query("BEGIN TRANSACTION");
862  try {
863  UserMetadata user;
864  if (!getMetadataForUser(name, user)) {
865  std::string const loggable = g_log_user_id ? std::string("") : name + ' ';
866  throw runtime_error("Cannot drop user. User " + loggable + "does not exist.");
867  }
868  dropRole_unsafe(name);
869  deleteObjectDescriptorMap(name);
870  const std::string& roleName(name);
871  sqliteConnector_->query_with_text_param("DELETE FROM mapd_roles WHERE userName = ?",
872  roleName);
873  sqliteConnector_->query("DELETE FROM mapd_users WHERE userid = " +
874  std::to_string(user.userId));
875  sqliteConnector_->query("DELETE FROM mapd_privileges WHERE userid = " +
876  std::to_string(user.userId));
877  } catch (const std::exception& e) {
878  sqliteConnector_->query("ROLLBACK TRANSACTION");
879  throw;
880  }
881  sqliteConnector_->query("END TRANSACTION");
882 }
883 
884 std::vector<std::shared_ptr<Catalog>> SysCatalog::getCatalogsForAllDbs() {
885  std::vector<std::shared_ptr<Catalog>> catalogs{};
886  const auto& db_metadata_list = getAllDBMetadata();
887  for (const auto& db_metadata : db_metadata_list) {
888  catalogs.emplace_back(getCatalog(
889  basePath_, db_metadata, dataMgr_, string_dict_hosts_, calciteMgr_, false));
890  }
891  return catalogs;
892 }
893 
894 namespace { // anonymous namespace
895 
896 auto append_with_commas = [](string& s, const string& t) {
897  if (!s.empty()) {
898  s += ", ";
899  }
900  s += t;
901 };
902 
903 } // anonymous namespace
904 
905 void SysCatalog::alterUser(const int32_t userid,
906  const string* passwd,
907  bool* issuper,
908  const string* dbname,
909  bool* can_login) {
911  sqliteConnector_->query("BEGIN TRANSACTION");
912  try {
913  string sql;
914  std::vector<std::string> values;
915  if (passwd != nullptr) {
916  append_with_commas(sql, "passwd_hash = ?");
917  values.push_back(hash_with_bcrypt(*passwd));
918  }
919  if (issuper != nullptr) {
920  append_with_commas(sql, "issuper = ?");
921  values.push_back(std::to_string(*issuper));
922  }
923  if (dbname != nullptr) {
924  if (!dbname->empty()) {
925  append_with_commas(sql, "default_db = ?");
926  DBMetadata db;
927  if (!SysCatalog::instance().getMetadataForDB(*dbname, db)) {
928  throw runtime_error(string("DEFAULT_DB ") + *dbname + " not found.");
929  }
930  values.push_back(std::to_string(db.dbId));
931  } else {
932  append_with_commas(sql, "default_db = NULL");
933  }
934  }
935  if (can_login != nullptr) {
936  append_with_commas(sql, "can_login = ?");
937  values.push_back(std::to_string(*can_login));
938  }
939 
940  sql = "UPDATE mapd_users SET " + sql + " WHERE userid = ?";
941  values.push_back(std::to_string(userid));
942 
943  sqliteConnector_->query_with_text_params(sql, values);
944  } catch (const std::exception& e) {
945  sqliteConnector_->query("ROLLBACK TRANSACTION");
946  throw;
947  }
948  sqliteConnector_->query("END TRANSACTION");
949 }
950 
951 auto SysCatalog::yieldTransactionStreamer() {
952  return
953  [](auto& db_connector, auto on_success, auto on_failure, auto&&... query_requests) {
954  auto query_runner = [&db_connector](auto&&... query_reqs) {
955  [[gnu::unused]] int throw_away[] = {
956  (db_connector->query_with_text_params(
957  std::forward<decltype(query_reqs)>(query_reqs)),
958  0)...};
959  };
960 
961  db_connector->query("BEGIN TRANSACTION");
962  try {
963  query_runner(std::forward<decltype(query_requests)>(query_requests)...);
964  on_success();
965  } catch (std::exception&) {
966  db_connector->query("ROLLBACK TRANSACTION");
967  on_failure();
968  throw;
969  }
970  db_connector->query("END TRANSACTION");
971  };
972 }
973 
974 void SysCatalog::updateUserRoleName(const std::string& roleName,
975  const std::string& newName) {
977 
978  auto it = granteeMap_.find(to_upper(roleName));
979  if (it != granteeMap_.end()) {
980  it->second->setName(newName);
981  std::swap(granteeMap_[to_upper(newName)], it->second);
982  granteeMap_.erase(it);
983  }
984 }
985 
986 void SysCatalog::renameUser(std::string const& old_name, std::string const& new_name) {
987  using namespace std::string_literals;
990 
991  UserMetadata old_user;
992  if (!getMetadataForUser(old_name, old_user)) {
993  std::string const loggable = g_log_user_id ? std::string("") : old_name + ' ';
994  throw std::runtime_error("User " + loggable + "doesn't exist.");
995  }
996 
997  UserMetadata new_user;
998  if (getMetadataForUser(new_name, new_user)) {
999  throw std::runtime_error("User " + new_user.userLoggable() + " already exists.");
1000  }
1001 
1002  if (getGrantee(new_name)) {
1003  std::string const loggable = g_log_user_id ? std::string("") : new_name + ' ';
1004  throw runtime_error(
1005  "Username " + loggable +
1006  "is same as one of existing grantees. User and role names should be unique.");
1007  }
1008 
1009  auto transaction_streamer = yieldTransactionStreamer();
1010  auto failure_handler = [] {};
1011  auto success_handler = [this, &old_name, &new_name] {
1012  updateUserRoleName(old_name, new_name);
1013  };
1014  auto q1 = {"UPDATE mapd_users SET name=?1 where name=?2;"s, new_name, old_name};
1015  auto q2 = {"UPDATE mapd_object_permissions set roleName=?1 WHERE roleName=?2;"s,
1016  new_name,
1017  old_name};
1018  transaction_streamer(sqliteConnector_, success_handler, failure_handler, q1, q2);
1019 }
1020 
1021 void SysCatalog::renameDatabase(std::string const& old_name,
1022  std::string const& new_name) {
1023  using namespace std::string_literals;
1024  sys_write_lock write_lock(this);
1026 
1027  DBMetadata new_db;
1028  if (getMetadataForDB(new_name, new_db)) {
1029  throw std::runtime_error("Database " + new_name + " already exists.");
1030  }
1031  if (to_upper(new_name) == to_upper(OMNISCI_SYSTEM_CATALOG)) {
1032  throw std::runtime_error("Database name " + new_name + "is reserved.");
1033  }
1034 
1035  DBMetadata old_db;
1036  if (!getMetadataForDB(old_name, old_db)) {
1037  throw std::runtime_error("Database " + old_name + " does not exists.");
1038  }
1039 
1040  removeCatalog(old_db.dbName);
1041 
1042  std::string old_catalog_path, new_catalog_path;
1043  std::tie(old_catalog_path, new_catalog_path) =
1044  duplicateAndRenameCatalog(old_name, new_name);
1045 
1046  auto transaction_streamer = yieldTransactionStreamer();
1047  auto failure_handler = [this, new_catalog_path] {
1048  removeCatalogByFullPath(new_catalog_path);
1049  };
1050  auto success_handler = [this, old_catalog_path] {
1051  removeCatalogByFullPath(old_catalog_path);
1052  };
1053 
1054  auto q1 = {"UPDATE mapd_databases SET name=?1 WHERE name=?2;"s, new_name, old_name};
1055  auto q2 = {
1056  "UPDATE mapd_object_permissions SET objectName=?1 WHERE objectNAME=?2 and (objectPermissionsType=?3 or objectId = -1) and dbId=?4;"s,
1057  new_name,
1058  old_name,
1060  std::to_string(old_db.dbId)};
1061 
1062  transaction_streamer(sqliteConnector_, success_handler, failure_handler, q1, q2);
1063 }
1064 
1065 void SysCatalog::createDatabase(const string& name, int owner) {
1066  sys_write_lock write_lock(this);
1068 
1069  DBMetadata db;
1070  if (getMetadataForDB(name, db)) {
1071  throw runtime_error("Database " + name + " already exists.");
1072  }
1073  if (to_upper(name) == to_upper(OMNISCI_SYSTEM_CATALOG)) {
1074  throw runtime_error("Database name " + name + " is reserved.");
1075  }
1076 
1077  std::unique_ptr<SqliteConnector> dbConn(
1078  new SqliteConnector(name, basePath_ + "/mapd_catalogs/"));
1079  // NOTE(max): it's okay to run this in a separate transaction. If we fail later
1080  // we delete the database anyways.
1081  // If we run it in the same transaction as SysCatalog functions, then Catalog
1082  // constructor won't find the tables we have just created.
1083  dbConn->query("BEGIN TRANSACTION");
1084  try {
1085  dbConn->query(
1086  "CREATE TABLE mapd_tables (tableid integer primary key, name text unique, userid "
1087  "integer, ncolumns integer, "
1088  "isview boolean, "
1089  "fragments text, frag_type integer, max_frag_rows integer, max_chunk_size "
1090  "bigint, "
1091  "frag_page_size integer, "
1092  "max_rows bigint, partitions text, shard_column_id integer, shard integer, "
1093  "sort_column_id integer default 0, storage_type text default '', "
1094  "max_rollback_epochs integer default -1, "
1095  "num_shards integer, key_metainfo TEXT, version_num "
1096  "BIGINT DEFAULT 1) ");
1097  dbConn->query(
1098  "CREATE TABLE mapd_columns (tableid integer references mapd_tables, columnid "
1099  "integer, name text, coltype "
1100  "integer, colsubtype integer, coldim integer, colscale integer, is_notnull "
1101  "boolean, compression integer, "
1102  "comp_param integer, size integer, chunks text, is_systemcol boolean, "
1103  "is_virtualcol boolean, virtual_expr "
1104  "text, is_deletedcol boolean, version_num BIGINT, "
1105  "primary key(tableid, columnid), unique(tableid, name))");
1106  dbConn->query(
1107  "CREATE TABLE mapd_views (tableid integer references mapd_tables, sql text)");
1108  dbConn->query(
1109  "CREATE TABLE mapd_dashboards (id integer primary key autoincrement, name text , "
1110  "userid integer references mapd_users, state text, image_hash text, update_time "
1111  "timestamp, "
1112  "metadata text, UNIQUE(userid, name) )");
1113  dbConn->query(
1114  "CREATE TABLE mapd_links (linkid integer primary key, userid integer references "
1115  "mapd_users, "
1116  "link text unique, view_state text, update_time timestamp, view_metadata text)");
1117  dbConn->query(
1118  "CREATE TABLE mapd_dictionaries (dictid integer primary key, name text unique, "
1119  "nbits int, is_shared boolean, "
1120  "refcount int, version_num BIGINT DEFAULT 1)");
1121  dbConn->query(
1122  "CREATE TABLE mapd_logical_to_physical(logical_table_id integer, "
1123  "physical_table_id "
1124  "integer)");
1125  dbConn->query("CREATE TABLE mapd_record_ownership_marker (dummy integer)");
1126  dbConn->query_with_text_params(
1127  "INSERT INTO mapd_record_ownership_marker (dummy) VALUES (?1)",
1128  std::vector<std::string>{std::to_string(owner)});
1129 
1130  if (g_enable_fsi) {
1131  dbConn->query(Catalog::getForeignServerSchema());
1132  dbConn->query(Catalog::getForeignTableSchema());
1133  }
1134  } catch (const std::exception&) {
1135  dbConn->query("ROLLBACK TRANSACTION");
1136  boost::filesystem::remove(basePath_ + "/mapd_catalogs/" + name);
1137  throw;
1138  }
1139  dbConn->query("END TRANSACTION");
1140 
1141  std::shared_ptr<Catalog> cat;
1142  // Now update SysCatalog with privileges and the new database
1143  sqliteConnector_->query("BEGIN TRANSACTION");
1144  try {
1145  sqliteConnector_->query_with_text_param(
1146  "INSERT INTO mapd_databases (name, owner) VALUES (?, " + std::to_string(owner) +
1147  ")",
1148  name);
1149  CHECK(getMetadataForDB(name, db));
1150 
1151  cat = getCatalog(basePath_, db, dataMgr_, string_dict_hosts_, calciteMgr_, true);
1152 
1153  if (owner != OMNISCI_ROOT_USER_ID) {
1155  object.loadKey(*cat);
1156  UserMetadata user;
1157  CHECK(getMetadataForUserById(owner, user));
1158  grantAllOnDatabase_unsafe(user.userName, object, *cat);
1159  }
1160  } catch (const std::exception&) {
1161  sqliteConnector_->query("ROLLBACK TRANSACTION");
1162  boost::filesystem::remove(basePath_ + "/mapd_catalogs/" + name);
1163  throw;
1164  }
1165  sqliteConnector_->query("END TRANSACTION");
1166 
1167  // force a migration on the new database
1168  removeCatalog(name);
1169  cat = getCatalog(basePath_, db, dataMgr_, string_dict_hosts_, calciteMgr_, false);
1170 
1171  if (g_enable_fsi) {
1172  try {
1173  cat->createDefaultServersIfNotExists();
1174  } catch (...) {
1175  boost::filesystem::remove(basePath_ + "/mapd_catalogs/" + name);
1176  throw;
1177  }
1178  }
1179 }
1180 
1181 void SysCatalog::dropDatabase(const DBMetadata& db) {
1182  sys_write_lock write_lock(this);
1184  auto cat = getCatalog(basePath_, db, dataMgr_, string_dict_hosts_, calciteMgr_, false);
1185  sqliteConnector_->query("BEGIN TRANSACTION");
1186  try {
1187  // remove this database ID from any users that have it set as their default database
1188  sqliteConnector_->query_with_text_param(
1189  "UPDATE mapd_users SET default_db = NULL WHERE default_db = ?",
1190  std::to_string(db.dbId));
1191  /* revoke object privileges to all tables of the database being dropped */
1192  const auto tables = cat->getAllTableMetadata();
1193  for (const auto table : tables) {
1194  if (table->shard >= 0) {
1195  // skip shards, they're not standalone tables
1196  continue;
1197  }
1198  revokeDBObjectPrivilegesFromAll_unsafe(
1199  DBObject(table->tableName, TableDBObjectType), cat.get());
1200  }
1201  const auto dashboards = cat->getAllDashboardsMetadata();
1202  for (const auto dashboard : dashboards) {
1203  revokeDBObjectPrivilegesFromAll_unsafe(
1204  DBObject(dashboard->dashboardId, DashboardDBObjectType), cat.get());
1205  }
1206  /* revoke object privileges to the database being dropped */
1207  for (const auto& grantee : granteeMap_) {
1208  if (grantee.second->hasAnyPrivilegesOnDb(db.dbId, true)) {
1209  revokeAllOnDatabase_unsafe(grantee.second->getName(), db.dbId, grantee.second);
1210  }
1211  }
1212  sqliteConnector_->query_with_text_param("DELETE FROM mapd_databases WHERE dbid = ?",
1213  std::to_string(db.dbId));
1214  cat->eraseDBData();
1215  removeCatalog(db.dbName);
1216  } catch (const std::exception&) {
1217  sqliteConnector_->query("ROLLBACK TRANSACTION");
1218  throw;
1219  }
1220  sqliteConnector_->query("END TRANSACTION");
1221 }
1222 
1223 // checkPasswordForUser() with no EE code
1224 bool SysCatalog::checkPasswordForUser(const std::string& passwd,
1225  std::string& name,
1226  UserMetadata& user) {
1227  return checkPasswordForUserImpl(passwd, name, user);
1228 }
1229 
1230 bool SysCatalog::checkPasswordForUserImpl(const std::string& passwd,
1231  std::string& name,
1232  UserMetadata& user) {
1233  sys_read_lock read_lock(this);
1234  if (!getMetadataForUser(name, user)) {
1235  // Check password against some fake hash just to waste time so that response times
1236  // for invalid password and invalid user are similar and a caller can't say the
1237  // difference
1238  char fake_hash[BCRYPT_HASHSIZE];
1239  CHECK(bcrypt_gensalt(-1, fake_hash) == 0);
1240  bcrypt_checkpw(passwd.c_str(), fake_hash);
1241  LOG(WARNING) << "Local login failed";
1242  return false;
1243  }
1244  int pwd_check_result = bcrypt_checkpw(passwd.c_str(), user.passwd_hash.c_str());
1245  // if the check fails there is a good chance that data on disc is broken
1246  CHECK(pwd_check_result >= 0);
1247  return pwd_check_result == 0;
1248 }
1249 
1250 static bool parseUserMetadataFromSQLite(const std::unique_ptr<SqliteConnector>& conn,
1251  UserMetadata& user) {
1252  int numRows = conn->getNumRows();
1253  if (numRows == 0) {
1254  return false;
1255  }
1256  user.userId = conn->getData<int>(0, 0);
1257  user.userName = conn->getData<string>(0, 1);
1258  user.passwd_hash = conn->getData<string>(0, 2);
1259  user.isSuper = conn->getData<bool>(0, 3);
1260  user.defaultDbId = conn->isNull(0, 4) ? -1 : conn->getData<int>(0, 4);
1261  if (conn->isNull(0, 5)) {
1262  LOG(WARNING)
1263  << "User property 'can_login' not set for user " << user.userLoggable()
1264  << ". Disabling login ability. Set the users login ability with \"ALTER USER "
1265  << (g_log_user_id ? std::string("[username]") : user.userName)
1266  << " (can_login='true');\".";
1267  }
1268  user.can_login = conn->isNull(0, 5) ? false : conn->getData<bool>(0, 5);
1269  return true;
1270 }
1271 
1272 bool SysCatalog::getMetadataForUser(const string& name, UserMetadata& user) {
1273  sys_read_lock read_lock(this);
1275  sqliteConnector_->query_with_text_param(
1276  "SELECT userid, name, passwd_hash, issuper, default_db, can_login FROM mapd_users "
1277  "WHERE name = ?",
1278  name);
1279  return parseUserMetadataFromSQLite(sqliteConnector_, user);
1280 }
1281 
1282 bool SysCatalog::getMetadataForUserById(const int32_t idIn, UserMetadata& user) {
1284  sqliteConnector_->query_with_text_param(
1285  "SELECT userid, name, passwd_hash, issuper, default_db, can_login FROM mapd_users "
1286  "WHERE userid = ?",
1287  std::to_string(idIn));
1288  return parseUserMetadataFromSQLite(sqliteConnector_, user);
1289 }
1290 
1291 list<DBMetadata> SysCatalog::getAllDBMetadata() {
1293  sqliteConnector_->query("SELECT dbid, name, owner FROM mapd_databases");
1294  int numRows = sqliteConnector_->getNumRows();
1295  list<DBMetadata> db_list;
1296  for (int r = 0; r < numRows; ++r) {
1297  DBMetadata db;
1298  db.dbId = sqliteConnector_->getData<int>(r, 0);
1299  db.dbName = sqliteConnector_->getData<string>(r, 1);
1300  db.dbOwner = sqliteConnector_->getData<int>(r, 2);
1301  db_list.push_back(db);
1302  }
1303  return db_list;
1304 }
1305 
1306 namespace {
1307 
1308 auto get_users(std::unique_ptr<SqliteConnector>& sqliteConnector,
1309  const int32_t dbId = -1) {
1310  sqliteConnector->query("SELECT userid, name, issuper, can_login FROM mapd_users");
1311  int numRows = sqliteConnector->getNumRows();
1312  list<UserMetadata> user_list;
1313  const bool return_all_users = dbId == -1;
1314  auto has_any_privilege = [&return_all_users, &dbId](const std::string& name) {
1315  if (!return_all_users) {
1316  const auto grantee = SysCatalog::instance().getUserGrantee(name);
1317  return grantee ? grantee->hasAnyPrivilegesOnDb(dbId, false) : false;
1318  }
1319  return true;
1320  };
1321  auto add_user = [&user_list, &has_any_privilege](const int32_t id,
1322  const std::string& name,
1323  const bool super,
1324  const bool can_login) {
1325  if (has_any_privilege(name)) {
1326  user_list.emplace_back(id, name, "", super, -1, can_login);
1327  };
1328  };
1329  for (int r = 0; r < numRows; ++r) {
1330  add_user(sqliteConnector->getData<int>(r, 0),
1331  sqliteConnector->getData<string>(r, 1),
1332  sqliteConnector->getData<bool>(r, 2),
1333  sqliteConnector->getData<bool>(r, 3));
1334  }
1335  return user_list;
1336 }
1337 
1338 } // namespace
1339 
1340 list<UserMetadata> SysCatalog::getAllUserMetadata(const int64_t dbId) {
1341  // this call is to return users that have some form of permissions to objects in the db
1342  // sadly mapd_object_permissions table is also misused to manage user roles.
1344  return get_users(sqliteConnector_, dbId);
1345 }
1346 
1347 list<UserMetadata> SysCatalog::getAllUserMetadata() {
1349  return get_users(sqliteConnector_);
1350 }
1351 
1352 void SysCatalog::getMetadataWithDefaultDB(std::string& dbname,
1353  const std::string& username,
1355  UserMetadata& user_meta) {
1356  sys_read_lock read_lock(this);
1357  if (!getMetadataForUser(username, user_meta)) {
1358  throw std::runtime_error("Invalid credentials.");
1359  }
1360 
1361  if (!dbname.empty()) {
1362  if (!getMetadataForDB(dbname, db_meta)) {
1363  throw std::runtime_error("Database name " + dbname + " does not exist.");
1364  }
1365  // loaded the requested database
1366  } else {
1367  if (user_meta.defaultDbId != -1) {
1368  if (!getMetadataForDBById(user_meta.defaultDbId, db_meta)) {
1369  std::string loggable = g_log_user_id ? std::string("") : ' ' + user_meta.userName;
1370  throw std::runtime_error(
1371  "Server error: User #" + std::to_string(user_meta.userId) + loggable +
1372  " has invalid default_db #" + std::to_string(user_meta.defaultDbId) +
1373  " which does not exist.");
1374  }
1375  dbname = db_meta.dbName;
1376  // loaded the user's default database
1377  } else {
1378  if (!getMetadataForDB(OMNISCI_DEFAULT_DB, db_meta)) {
1379  throw std::runtime_error(std::string("Database ") + OMNISCI_DEFAULT_DB +
1380  " does not exist.");
1381  }
1382  dbname = OMNISCI_DEFAULT_DB;
1383  // loaded the mapd database by default
1384  }
1385  }
1386 }
1387 
1388 bool SysCatalog::getMetadataForDB(const string& name, DBMetadata& db) {
1389  sys_read_lock read_lock(this);
1391  sqliteConnector_->query_with_text_param(
1392  "SELECT dbid, name, owner FROM mapd_databases WHERE name = ?", name);
1393  int numRows = sqliteConnector_->getNumRows();
1394  if (numRows == 0) {
1395  return false;
1396  }
1397  db.dbId = sqliteConnector_->getData<int>(0, 0);
1398  db.dbName = sqliteConnector_->getData<string>(0, 1);
1399  db.dbOwner = sqliteConnector_->getData<int>(0, 2);
1400  return true;
1401 }
1402 
1403 bool SysCatalog::getMetadataForDBById(const int32_t idIn, DBMetadata& db) {
1405  sqliteConnector_->query_with_text_param(
1406  "SELECT dbid, name, owner FROM mapd_databases WHERE dbid = ?",
1407  std::to_string(idIn));
1408  int numRows = sqliteConnector_->getNumRows();
1409  if (numRows == 0) {
1410  return false;
1411  }
1412  db.dbId = sqliteConnector_->getData<int>(0, 0);
1413  db.dbName = sqliteConnector_->getData<string>(0, 1);
1414  db.dbOwner = sqliteConnector_->getData<int>(0, 2);
1415  return true;
1416 }
1417 
1418 DBSummaryList SysCatalog::getDatabaseListForUser(const UserMetadata& user) {
1419  DBSummaryList ret;
1420 
1421  std::list<Catalog_Namespace::DBMetadata> db_list = getAllDBMetadata();
1422  std::list<Catalog_Namespace::UserMetadata> user_list = getAllUserMetadata();
1423 
1424  for (auto d : db_list) {
1425  DBObject dbObject(d.dbName, DatabaseDBObjectType);
1426  dbObject.loadKey();
1428  if (!checkPrivileges(user, std::vector<DBObject>{dbObject})) {
1429  continue;
1430  }
1431  for (auto u : user_list) {
1432  if (d.dbOwner == u.userId) {
1433  ret.emplace_back(DBSummary{d.dbName, u.userName});
1434  break;
1435  }
1436  }
1437  }
1438 
1439  return ret;
1440 }
1441 
1442 void SysCatalog::createDBObject(const UserMetadata& user,
1443  const std::string& objectName,
1445  const Catalog_Namespace::Catalog& catalog,
1446  int32_t objectId) {
1447  sys_write_lock write_lock(this);
1449 
1450  DBObject object =
1451  objectId == -1 ? DBObject(objectName, type) : DBObject(objectId, type);
1452  object.loadKey(catalog);
1453  switch (type) {
1454  case TableDBObjectType:
1455  object.setPrivileges(AccessPrivileges::ALL_TABLE);
1456  break;
1457  case DashboardDBObjectType:
1458  object.setPrivileges(AccessPrivileges::ALL_DASHBOARD);
1459  break;
1460  case ServerDBObjectType:
1461  object.setPrivileges(AccessPrivileges::ALL_SERVER);
1462  break;
1463  default:
1464  object.setPrivileges(AccessPrivileges::ALL_DATABASE);
1465  break;
1466  }
1467  object.setOwner(user.userId);
1468  sqliteConnector_->query("BEGIN TRANSACTION");
1469  try {
1470  if (!user.isSuper) { // no need to grant to suser, has all privs by default
1471  grantDBObjectPrivileges_unsafe(user.userName, object, catalog);
1472  auto* grantee = instance().getUserGrantee(user.userName);
1473  if (!grantee) {
1474  throw runtime_error("Cannot create DBObject. User " + user.userLoggable() +
1475  " does not exist.");
1476  }
1477  grantee->grantPrivileges(object);
1478  }
1479  } catch (std::exception& e) {
1480  sqliteConnector_->query("ROLLBACK TRANSACTION");
1481  throw;
1482  }
1483  sqliteConnector_->query("END TRANSACTION");
1484 }
1485 
1486 void SysCatalog::renameDBObject(const std::string& objectName,
1487  const std::string& newName,
1489  int32_t objectId,
1490  const Catalog_Namespace::Catalog& catalog) {
1491  sys_write_lock write_lock(this);
1492  DBObject new_object(newName, type);
1493  DBObjectKey key;
1494  key.dbId = catalog.getCurrentDB().dbId;
1495  key.objectId = objectId;
1496  key.permissionType = type;
1497  new_object.setObjectKey(key);
1498  auto objdescs =
1499  getMetadataForObject(key.dbId, static_cast<int32_t>(type), key.objectId);
1500  for (auto obj : objdescs) {
1501  Grantee* grnt = getGrantee(obj->roleName);
1502  if (grnt) {
1503  grnt->renameDbObject(new_object);
1504  }
1505  }
1506  renameObjectsInDescriptorMap(new_object, catalog);
1507 }
1508 
1509 void SysCatalog::grantDBObjectPrivilegesBatch_unsafe(
1510  const vector<string>& grantees,
1511  const vector<DBObject>& objects,
1512  const Catalog_Namespace::Catalog& catalog) {
1513  for (const auto& grantee : grantees) {
1514  for (const auto& object : objects) {
1515  grantDBObjectPrivileges_unsafe(grantee, object, catalog);
1516  }
1517  }
1518 }
1519 
1520 // GRANT INSERT ON TABLE payroll_table TO payroll_dept_role;
1521 void SysCatalog::grantDBObjectPrivileges_unsafe(
1522  const std::string& granteeName,
1523  DBObject object,
1524  const Catalog_Namespace::Catalog& catalog) {
1525  object.loadKey(catalog);
1526  CHECK(object.valid());
1527  if (object.getPrivileges().hasPermission(DatabasePrivileges::ALL) &&
1528  object.getObjectKey().permissionType == DatabaseDBObjectType) {
1529  return grantAllOnDatabase_unsafe(granteeName, object, catalog);
1530  }
1531 
1532  sys_write_lock write_lock(this);
1533 
1534  UserMetadata user_meta;
1535  if (instance().getMetadataForUser(granteeName, user_meta)) {
1536  if (user_meta.isSuper) {
1537  // super doesn't have explicit privileges so nothing to do
1538  return;
1539  }
1540  }
1541  auto* grantee = instance().getGrantee(granteeName);
1542  if (!grantee) {
1543  throw runtime_error("Request to grant privileges to " + granteeName +
1544  " failed because role or user with this name does not exist.");
1545  }
1546  grantee->grantPrivileges(object);
1547 
1548  /* apply grant privileges statement to sqlite DB */
1549  std::vector<std::string> objectKey = object.toString();
1550  object.resetPrivileges();
1551  grantee->getPrivileges(object, true);
1552 
1555  sqliteConnector_, granteeName, grantee->isUser(), object);
1556  updateObjectDescriptorMap(granteeName, object, grantee->isUser(), catalog);
1557 }
1558 
1559 void SysCatalog::grantAllOnDatabase_unsafe(const std::string& roleName,
1560  DBObject& object,
1561  const Catalog_Namespace::Catalog& catalog) {
1562  // It's a separate use case because it's easier for implementation to convert ALL ON
1563  // DATABASE into ALL ON DASHBOARDS, ALL ON VIEWS and ALL ON TABLES
1564  // Add DB Access privileges
1565  DBObject tmp_object = object;
1568  grantDBObjectPrivileges_unsafe(roleName, tmp_object, catalog);
1571  grantDBObjectPrivileges_unsafe(roleName, tmp_object, catalog);
1574  grantDBObjectPrivileges_unsafe(roleName, tmp_object, catalog);
1576  tmp_object.setPermissionType(ViewDBObjectType);
1577  grantDBObjectPrivileges_unsafe(roleName, tmp_object, catalog);
1578 
1579  if (g_enable_fsi) {
1582  grantDBObjectPrivileges_unsafe(roleName, tmp_object, catalog);
1583  }
1584 
1587  grantDBObjectPrivileges_unsafe(roleName, tmp_object, catalog);
1588  return;
1589 }
1590 
1591 void SysCatalog::revokeDBObjectPrivilegesBatch_unsafe(
1592  const vector<string>& grantees,
1593  const vector<DBObject>& objects,
1594  const Catalog_Namespace::Catalog& catalog) {
1595  for (const auto& grantee : grantees) {
1596  for (const auto& object : objects) {
1597  revokeDBObjectPrivileges_unsafe(grantee, object, catalog);
1598  }
1599  }
1600 }
1601 
1602 void SysCatalog::revokeDBObjectPrivilegesFromAllBatch_unsafe(
1603  vector<DBObject>& objects,
1604  Catalog_Namespace::Catalog* catalog) {
1605  for (const auto& object : objects) {
1606  revokeDBObjectPrivilegesFromAll_unsafe(object, catalog);
1607  }
1608 }
1609 
1610 // REVOKE INSERT ON TABLE payroll_table FROM payroll_dept_role;
1611 void SysCatalog::revokeDBObjectPrivileges_unsafe(
1612  const std::string& granteeName,
1613  DBObject object,
1614  const Catalog_Namespace::Catalog& catalog) {
1615  sys_write_lock write_lock(this);
1616 
1617  UserMetadata user_meta;
1618  if (instance().getMetadataForUser(granteeName, user_meta)) {
1619  if (user_meta.isSuper) {
1620  // super doesn't have explicit privileges so nothing to do
1621  return;
1622  }
1623  }
1624  auto* grantee = getGrantee(granteeName);
1625  if (!grantee) {
1626  throw runtime_error("Request to revoke privileges from " + granteeName +
1627  " failed because role or user with this name does not exist.");
1628  }
1629  object.loadKey(catalog);
1630 
1631  if (object.getPrivileges().hasPermission(DatabasePrivileges::ALL) &&
1632  object.getObjectKey().permissionType == DatabaseDBObjectType) {
1633  return revokeAllOnDatabase_unsafe(granteeName, object.getObjectKey().dbId, grantee);
1634  }
1635 
1636  auto ret_object = grantee->revokePrivileges(object);
1637  if (ret_object) {
1640  sqliteConnector_, granteeName, grantee->isUser(), *ret_object);
1641  updateObjectDescriptorMap(granteeName, *ret_object, grantee->isUser(), catalog);
1642  } else {
1644  deleteObjectPrivileges(sqliteConnector_, granteeName, grantee->isUser(), object);
1645  deleteObjectDescriptorMap(granteeName, object, catalog);
1646  }
1647 }
1648 
1649 void SysCatalog::revokeAllOnDatabase_unsafe(const std::string& roleName,
1650  int32_t dbId,
1651  Grantee* grantee) {
1653  sqliteConnector_->query_with_text_params(
1654  "DELETE FROM mapd_object_permissions WHERE roleName = ?1 and dbId = ?2",
1655  std::vector<std::string>{roleName, std::to_string(dbId)});
1656  grantee->revokeAllOnDatabase(dbId);
1657  for (auto d = objectDescriptorMap_.begin(); d != objectDescriptorMap_.end();) {
1658  if (d->second->roleName == roleName && d->second->dbId == dbId) {
1659  delete d->second;
1660  d = objectDescriptorMap_.erase(d);
1661  } else {
1662  d++;
1663  }
1664  }
1665 }
1666 
1667 void SysCatalog::revokeDBObjectPrivilegesFromAll_unsafe(DBObject dbObject,
1668  Catalog* catalog) {
1669  sys_write_lock write_lock(this);
1670  dbObject.loadKey(*catalog);
1671  auto privs = (dbObject.getObjectKey().permissionType == TableDBObjectType)
1676  dbObject.setPrivileges(privs);
1677  for (const auto& grantee : granteeMap_) {
1678  if (grantee.second->findDbObject(dbObject.getObjectKey(), true)) {
1679  revokeDBObjectPrivileges_unsafe(grantee.second->getName(), dbObject, *catalog);
1680  }
1681  }
1682 }
1683 
1684 bool SysCatalog::verifyDBObjectOwnership(const UserMetadata& user,
1685  DBObject object,
1686  const Catalog_Namespace::Catalog& catalog) {
1687  sys_read_lock read_lock(this);
1688 
1689  auto* grantee = instance().getUserGrantee(user.userName);
1690  if (grantee) {
1691  object.loadKey(catalog);
1692  auto* found_object = grantee->findDbObject(object.getObjectKey(), false);
1693  if (found_object && found_object->getOwner() == user.userId) {
1694  return true;
1695  }
1696  }
1697  return false;
1698 }
1699 
1700 void SysCatalog::changeDBObjectOwnership(const UserMetadata& new_owner,
1701  const UserMetadata& previous_owner,
1702  DBObject object,
1703  const Catalog_Namespace::Catalog& catalog,
1704  bool revoke_privileges) {
1705  sys_write_lock write_lock(this);
1707  object.loadKey(catalog);
1708  switch (object.getType()) {
1709  case TableDBObjectType:
1710  object.setPrivileges(AccessPrivileges::ALL_TABLE);
1711  break;
1712  case DashboardDBObjectType:
1713  object.setPrivileges(AccessPrivileges::ALL_DASHBOARD);
1714  break;
1715  case ServerDBObjectType:
1716  object.setPrivileges(AccessPrivileges::ALL_SERVER);
1717  break;
1718  case DatabaseDBObjectType:
1719  object.setPrivileges(AccessPrivileges::ALL_DATABASE);
1720  break;
1721  case ViewDBObjectType:
1722  object.setPrivileges(AccessPrivileges::ALL_VIEW);
1723  break;
1724  default:
1725  UNREACHABLE(); // unkown object type
1726  break;
1727  }
1728  sqliteConnector_->query("BEGIN TRANSACTION");
1729  try {
1730  if (!new_owner.isSuper) { // no need to grant to suser, has all privs by default
1731  grantDBObjectPrivileges_unsafe(new_owner.userName, object, catalog);
1732  }
1733  if (!previous_owner.isSuper && revoke_privileges) { // no need to revoke from suser
1734  revokeDBObjectPrivileges_unsafe(previous_owner.userName, object, catalog);
1735  }
1736  } catch (std::exception& e) {
1737  sqliteConnector_->query("ROLLBACK TRANSACTION");
1738  throw;
1739  }
1740  sqliteConnector_->query("END TRANSACTION");
1741  object.setOwner(new_owner.userId); // change owner if no exceptions happen
1742 }
1743 
1744 void SysCatalog::getDBObjectPrivileges(const std::string& granteeName,
1745  DBObject& object,
1746  const Catalog_Namespace::Catalog& catalog) const {
1747  sys_read_lock read_lock(this);
1748  UserMetadata user_meta;
1749 
1750  if (instance().getMetadataForUser(granteeName, user_meta)) {
1751  if (user_meta.isSuper) {
1752  throw runtime_error(
1753  "Request to show privileges from " + granteeName +
1754  " failed because user is super user and has all privileges by default.");
1755  }
1756  }
1757  auto* grantee = instance().getGrantee(granteeName);
1758  if (!grantee) {
1759  throw runtime_error("Request to show privileges for " + granteeName +
1760  " failed because role or user with this name does not exist.");
1761  }
1762  object.loadKey(catalog);
1763  grantee->getPrivileges(object, true);
1764 }
1765 
1766 void SysCatalog::createRole_unsafe(const std::string& roleName,
1767  const bool userPrivateRole) {
1768  sys_write_lock write_lock(this);
1769 
1770  auto* grantee = getGrantee(roleName);
1771  if (grantee) {
1772  throw std::runtime_error("CREATE ROLE " + roleName +
1773  " failed because grantee with this name already exists.");
1774  }
1775  if (userPrivateRole) {
1776  grantee = new User(roleName);
1777  } else {
1778  grantee = new Role(roleName);
1779  }
1780  granteeMap_[to_upper(roleName)] = grantee;
1781 
1782  // NOTE (max): Why create an empty privileges record for a role?
1783  /* grant none privileges to this role and add it to sqlite DB */
1785  DBObjectKey objKey;
1786  // 0 is an id that does not exist
1787  objKey.dbId = 0;
1789  dbObject.setObjectKey(objKey);
1790  grantee->grantPrivileges(dbObject);
1791 
1793  insertOrUpdateObjectPrivileges(sqliteConnector_, roleName, userPrivateRole, dbObject);
1794 }
1795 
1796 void SysCatalog::dropRole_unsafe(const std::string& roleName) {
1797  sys_write_lock write_lock(this);
1798 
1799  // it may very well be a user "role", so keep it generic
1800  auto* rl = getGrantee(roleName);
1801  if (rl) { // admin super user may not exist in roles
1802  delete rl;
1803  }
1804  granteeMap_.erase(to_upper(roleName));
1805 
1807  sqliteConnector_->query_with_text_param("DELETE FROM mapd_roles WHERE roleName = ?",
1808  roleName);
1809  sqliteConnector_->query_with_text_param(
1810  "DELETE FROM mapd_object_permissions WHERE roleName = ?", roleName);
1811 }
1812 
1813 void SysCatalog::grantRoleBatch_unsafe(const std::vector<std::string>& roles,
1814  const std::vector<std::string>& grantees) {
1815  for (const auto& role : roles) {
1816  for (const auto& grantee : grantees) {
1817  grantRole_unsafe(role, grantee);
1818  }
1819  }
1820 }
1821 
1822 // GRANT ROLE payroll_dept_role TO joe;
1823 void SysCatalog::grantRole_unsafe(const std::string& roleName,
1824  const std::string& granteeName) {
1825  auto* rl = getRoleGrantee(roleName);
1826  if (!rl) {
1827  throw runtime_error("Request to grant role " + roleName +
1828  " failed because role with this name does not exist.");
1829  }
1830  auto* grantee = getGrantee(granteeName);
1831  if (!grantee) {
1832  throw runtime_error("Request to grant role " + roleName + " failed because grantee " +
1833  granteeName + " does not exist.");
1834  }
1835  sys_write_lock write_lock(this);
1836  if (!grantee->hasRole(rl, true)) {
1837  grantee->grantRole(rl);
1839  sqliteConnector_->query_with_text_params(
1840  "INSERT INTO mapd_roles(roleName, userName) VALUES (?, ?)",
1841  std::vector<std::string>{rl->getName(), grantee->getName()});
1842  }
1843 }
1844 
1845 void SysCatalog::revokeRoleBatch_unsafe(const std::vector<std::string>& roles,
1846  const std::vector<std::string>& grantees) {
1847  for (const auto& role : roles) {
1848  for (const auto& grantee : grantees) {
1849  revokeRole_unsafe(role, grantee);
1850  }
1851  }
1852 }
1853 
1854 // REVOKE ROLE payroll_dept_role FROM joe;
1855 void SysCatalog::revokeRole_unsafe(const std::string& roleName,
1856  const std::string& granteeName) {
1857  auto* rl = getRoleGrantee(roleName);
1858  if (!rl) {
1859  throw runtime_error("Request to revoke role " + roleName +
1860  " failed because role with this name does not exist.");
1861  }
1862  auto* grantee = getGrantee(granteeName);
1863  if (!grantee) {
1864  throw runtime_error("Request to revoke role from " + granteeName +
1865  " failed because grantee with this name does not exist.");
1866  }
1867  sys_write_lock write_lock(this);
1868  grantee->revokeRole(rl);
1870  sqliteConnector_->query_with_text_params(
1871  "DELETE FROM mapd_roles WHERE roleName = ? AND userName = ?",
1872  std::vector<std::string>{rl->getName(), grantee->getName()});
1873 }
1874 
1875 // Update or add element in ObjectRoleDescriptorMap
1876 void SysCatalog::updateObjectDescriptorMap(const std::string& roleName,
1877  DBObject& object,
1878  bool roleType,
1880  bool present = false;
1881  auto privs = object.getPrivileges();
1882  sys_write_lock write_lock(this);
1883  auto range = objectDescriptorMap_.equal_range(
1884  std::to_string(cat.getCurrentDB().dbId) + ":" +
1885  std::to_string(object.getObjectKey().permissionType) + ":" +
1886  std::to_string(object.getObjectKey().objectId));
1887  for (auto d = range.first; d != range.second; ++d) {
1888  if (d->second->roleName == roleName) {
1889  // overwrite permissions
1890  d->second->privs = privs;
1891  present = true;
1892  }
1893  }
1894  if (!present) {
1896  od->roleName = roleName;
1897  od->roleType = roleType;
1898  od->objectType = object.getObjectKey().permissionType;
1899  od->dbId = object.getObjectKey().dbId;
1900  od->objectId = object.getObjectKey().objectId;
1901  od->privs = object.getPrivileges();
1902  od->objectOwnerId = object.getOwner();
1903  od->objectName = object.getName();
1904  objectDescriptorMap_.insert(ObjectRoleDescriptorMap::value_type(
1905  std::to_string(od->dbId) + ":" + std::to_string(od->objectType) + ":" +
1906  std::to_string(od->objectId),
1907  od));
1908  }
1909 }
1910 
1911 // rename object descriptors
1912 void SysCatalog::renameObjectsInDescriptorMap(DBObject& object,
1914  sys_write_lock write_lock(this);
1916  auto range = objectDescriptorMap_.equal_range(
1917  std::to_string(cat.getCurrentDB().dbId) + ":" +
1918  std::to_string(object.getObjectKey().permissionType) + ":" +
1919  std::to_string(object.getObjectKey().objectId));
1920  for (auto d = range.first; d != range.second; ++d) {
1921  // rename object
1922  d->second->objectName = object.getName();
1923  }
1924 
1925  sqliteConnector_->query("BEGIN TRANSACTION");
1926  try {
1927  sqliteConnector_->query_with_text_params(
1928  "UPDATE mapd_object_permissions SET objectName = ?1 WHERE "
1929  "dbId = ?2 AND objectId = ?3",
1930  std::vector<std::string>{object.getName(),
1932  std::to_string(object.getObjectKey().objectId)});
1933  } catch (const std::exception& e) {
1934  sqliteConnector_->query("ROLLBACK TRANSACTION");
1935  throw;
1936  }
1937  sqliteConnector_->query("END TRANSACTION");
1938 }
1939 
1940 // Remove user/role from ObjectRoleDescriptorMap
1941 void SysCatalog::deleteObjectDescriptorMap(const std::string& roleName) {
1942  sys_write_lock write_lock(this);
1943 
1944  for (auto d = objectDescriptorMap_.begin(); d != objectDescriptorMap_.end();) {
1945  if (d->second->roleName == roleName) {
1946  delete d->second;
1947  d = objectDescriptorMap_.erase(d);
1948  } else {
1949  d++;
1950  }
1951  }
1952 }
1953 
1954 // Remove element from ObjectRoleDescriptorMap
1955 void SysCatalog::deleteObjectDescriptorMap(const std::string& roleName,
1956  DBObject& object,
1957  const Catalog_Namespace::Catalog& cat) {
1958  sys_write_lock write_lock(this);
1959  auto range = objectDescriptorMap_.equal_range(
1960  std::to_string(cat.getCurrentDB().dbId) + ":" +
1961  std::to_string(object.getObjectKey().permissionType) + ":" +
1962  std::to_string(object.getObjectKey().objectId));
1963  for (auto d = range.first; d != range.second;) {
1964  // remove the entry
1965  if (d->second->roleName == roleName) {
1966  delete d->second;
1967  d = objectDescriptorMap_.erase(d);
1968  } else {
1969  d++;
1970  }
1971  }
1972 }
1973 
1974 bool SysCatalog::hasAnyPrivileges(const UserMetadata& user,
1975  std::vector<DBObject>& privObjects) {
1976  sys_read_lock read_lock(this);
1977  if (user.isSuper) {
1978  return true;
1979  }
1980  auto* user_rl = instance().getUserGrantee(user.userName);
1981  if (!user_rl) {
1982  throw runtime_error("Cannot check privileges. User " + user.userLoggable() +
1983  " does not exist.");
1984  }
1985  for (std::vector<DBObject>::iterator objectIt = privObjects.begin();
1986  objectIt != privObjects.end();
1987  ++objectIt) {
1988  if (!user_rl->hasAnyPrivileges(*objectIt, false)) {
1989  return false;
1990  }
1991  }
1992  return true;
1993 }
1994 
1995 bool SysCatalog::checkPrivileges(const UserMetadata& user,
1996  const std::vector<DBObject>& privObjects) const {
1997  sys_read_lock read_lock(this);
1998  if (user.isSuper) {
1999  return true;
2000  }
2001 
2002  auto* user_rl = instance().getUserGrantee(user.userName);
2003  if (!user_rl) {
2004  throw runtime_error("Cannot check privileges. User " + user.userLoggable() +
2005  " does not exist.");
2006  }
2007  for (auto& object : privObjects) {
2008  if (!user_rl->checkPrivileges(object)) {
2009  return false;
2010  }
2011  }
2012  return true;
2013 }
2014 
2015 bool SysCatalog::checkPrivileges(const std::string& userName,
2016  const std::vector<DBObject>& privObjects) const {
2017  UserMetadata user;
2018  if (!instance().getMetadataForUser(userName, user)) {
2019  std::string const loggable = g_log_user_id ? std::string("") : userName + ' ';
2020  throw runtime_error("Request to check privileges for user " + loggable +
2021  "failed because user with this name does not exist.");
2022  }
2023  return (checkPrivileges(user, privObjects));
2024 }
2025 
2026 Grantee* SysCatalog::getGrantee(const std::string& name) const {
2027  sys_read_lock read_lock(this);
2028  auto grantee = granteeMap_.find(to_upper(name));
2029  if (grantee == granteeMap_.end()) { // check to make sure role exists
2030  return nullptr;
2031  }
2032  return grantee->second; // returns pointer to role
2033 }
2034 
2035 Role* SysCatalog::getRoleGrantee(const std::string& name) const {
2036  return dynamic_cast<Role*>(getGrantee(name));
2037 }
2038 
2039 User* SysCatalog::getUserGrantee(const std::string& name) const {
2040  return dynamic_cast<User*>(getGrantee(name));
2041 }
2042 
2043 std::vector<ObjectRoleDescriptor*>
2044 SysCatalog::getMetadataForObject(int32_t dbId, int32_t dbType, int32_t objectId) const {
2045  sys_read_lock read_lock(this);
2046  std::vector<ObjectRoleDescriptor*> objectsList;
2047 
2048  auto range = objectDescriptorMap_.equal_range(std::to_string(dbId) + ":" +
2049  std::to_string(dbType) + ":" +
2050  std::to_string(objectId));
2051  for (auto d = range.first; d != range.second; ++d) {
2052  objectsList.push_back(d->second);
2053  }
2054  return objectsList; // return pointers to objects
2055 }
2056 
2057 bool SysCatalog::isRoleGrantedToGrantee(const std::string& granteeName,
2058  const std::string& roleName,
2059  bool only_direct) const {
2060  sys_read_lock read_lock(this);
2061  if (roleName == granteeName) {
2062  return true;
2063  }
2064  bool is_role_granted = false;
2065  auto* target_role = instance().getRoleGrantee(roleName);
2066  auto has_role = [&](auto grantee_rl) {
2067  is_role_granted = target_role && grantee_rl->hasRole(target_role, only_direct);
2068  };
2069  if (auto* user_role = instance().getUserGrantee(granteeName); user_role) {
2070  has_role(user_role);
2071  } else if (auto* role = instance().getRoleGrantee(granteeName); role) {
2072  has_role(role);
2073  } else {
2074  CHECK(false);
2075  }
2076  return is_role_granted;
2077 }
2078 
2079 bool SysCatalog::isDashboardSystemRole(const std::string& roleName) {
2080  return boost::algorithm::ends_with(roleName, SYSTEM_ROLE_TAG);
2081 }
2082 
2083 std::vector<std::string> SysCatalog::getRoles(const std::string& userName,
2084  const int32_t dbId) {
2085  sys_sqlite_lock sqlite_lock(this);
2086  std::string sql =
2087  "SELECT DISTINCT roleName FROM mapd_object_permissions WHERE "
2088  "objectPermissions<>0 "
2089  "AND roleType=0 AND dbId=" +
2090  std::to_string(dbId);
2091  sqliteConnector_->query(sql);
2092  int numRows = sqliteConnector_->getNumRows();
2093  std::vector<std::string> roles(0);
2094  for (int r = 0; r < numRows; ++r) {
2095  auto roleName = sqliteConnector_->getData<string>(r, 0);
2096  if (isRoleGrantedToGrantee(userName, roleName, false) &&
2097  !isDashboardSystemRole(roleName)) {
2098  roles.push_back(roleName);
2099  }
2100  }
2101  return roles;
2102 }
2103 
2104 std::vector<std::string> SysCatalog::getRoles(bool userPrivateRole,
2105  bool isSuper,
2106  const std::string& userName) {
2107  sys_read_lock read_lock(this);
2108  std::vector<std::string> roles;
2109  for (auto& grantee : granteeMap_) {
2110  if (!userPrivateRole && grantee.second->isUser()) {
2111  continue;
2112  }
2113  if (!isSuper && !isRoleGrantedToGrantee(userName, grantee.second->getName(), false)) {
2114  continue;
2115  }
2116  if (isDashboardSystemRole(grantee.second->getName())) {
2117  continue;
2118  }
2119  roles.push_back(grantee.second->getName());
2120  }
2121  return roles;
2122 }
2123 
2124 void SysCatalog::revokeDashboardSystemRole(const std::string roleName,
2125  const std::vector<std::string> grantees) {
2126  auto* rl = getRoleGrantee(roleName);
2127  for (auto granteeName : grantees) {
2128  const auto* grantee = SysCatalog::instance().getGrantee(granteeName);
2129  if (rl && grantee->hasRole(rl, true)) {
2130  // Grantees existence have been already validated
2131  SysCatalog::instance().revokeRole(roleName, granteeName);
2132  }
2133  }
2134 }
2135 
2136 void SysCatalog::buildRoleMap() {
2137  sys_write_lock write_lock(this);
2138  sys_sqlite_lock sqlite_lock(this);
2139  string roleQuery(
2140  "SELECT roleName, roleType, objectPermissionsType, dbId, objectId, "
2141  "objectPermissions, objectOwnerId, objectName "
2142  "from mapd_object_permissions");
2143  sqliteConnector_->query(roleQuery);
2144  size_t numRows = sqliteConnector_->getNumRows();
2145  std::vector<std::string> objectKeyStr(4);
2146  DBObjectKey objectKey;
2147  AccessPrivileges privs;
2148  bool userPrivateRole{false};
2149  for (size_t r = 0; r < numRows; ++r) {
2150  std::string roleName = sqliteConnector_->getData<string>(r, 0);
2151  userPrivateRole = sqliteConnector_->getData<bool>(r, 1);
2152  DBObjectType permissionType =
2153  static_cast<DBObjectType>(sqliteConnector_->getData<int>(r, 2));
2154  objectKeyStr[0] = sqliteConnector_->getData<string>(r, 2);
2155  objectKeyStr[1] = sqliteConnector_->getData<string>(r, 3);
2156  objectKeyStr[2] = sqliteConnector_->getData<string>(r, 4);
2157  objectKey = DBObjectKey::fromString(objectKeyStr, permissionType);
2158  privs.privileges = sqliteConnector_->getData<int>(r, 5);
2159  int32_t owner = sqliteConnector_->getData<int>(r, 6);
2160  std::string name = sqliteConnector_->getData<string>(r, 7);
2161 
2162  DBObject dbObject(objectKey, privs, owner);
2163  dbObject.setName(name);
2164  if (-1 == objectKey.objectId) {
2165  dbObject.setObjectType(DBObjectType::DatabaseDBObjectType);
2166  } else {
2167  dbObject.setObjectType(permissionType);
2168  }
2169 
2170  auto* rl = getGrantee(roleName);
2171  if (!rl) {
2172  if (userPrivateRole) {
2173  rl = new User(roleName);
2174  } else {
2175  rl = new Role(roleName);
2176  }
2177  granteeMap_[to_upper(roleName)] = rl;
2178  }
2179  rl->grantPrivileges(dbObject);
2180  }
2181 }
2182 
2183 void SysCatalog::populateRoleDbObjects(const std::vector<DBObject>& objects) {
2184  sys_write_lock write_lock(this);
2185  sys_sqlite_lock sqlite_lock(this);
2186  sqliteConnector_->query("BEGIN TRANSACTION");
2187  try {
2188  for (auto dbobject : objects) {
2189  UserMetadata user;
2190  CHECK(getMetadataForUserById(dbobject.getOwner(), user));
2191  auto* grantee = getUserGrantee(user.userName);
2192  if (grantee) {
2194  sqliteConnector_, grantee->getName(), true, dbobject);
2195  grantee->grantPrivileges(dbobject);
2196  }
2197  }
2198 
2199  } catch (const std::exception& e) {
2200  sqliteConnector_->query("ROLLBACK TRANSACTION");
2201  throw;
2202  }
2203  sqliteConnector_->query("END TRANSACTION");
2204 }
2205 
2206 void SysCatalog::buildUserRoleMap() {
2207  sys_write_lock write_lock(this);
2208  sys_sqlite_lock sqlite_lock(this);
2209  std::vector<std::pair<std::string, std::string>> granteeRooles;
2210  string userRoleQuery("SELECT roleName, userName from mapd_roles");
2211  sqliteConnector_->query(userRoleQuery);
2212  size_t numRows = sqliteConnector_->getNumRows();
2213  for (size_t r = 0; r < numRows; ++r) {
2214  std::string roleName = sqliteConnector_->getData<string>(r, 0);
2215  std::string userName = sqliteConnector_->getData<string>(r, 1);
2216  // required for declared nomenclature before v4.0.0
2217  if ((boost::equals(roleName, "mapd_default_suser_role") &&
2218  boost::equals(userName, OMNISCI_ROOT_USER)) ||
2219  (boost::equals(roleName, "mapd_default_user_role") &&
2220  !boost::equals(userName, "mapd_default_user_role"))) {
2221  // grouprole already exists with roleName==userName in mapd_roles table
2222  // ignore duplicate instances of userRole which exists before v4.0.0
2223  continue;
2224  }
2225  auto* rl = getGrantee(roleName);
2226  if (!rl) {
2227  throw runtime_error("Data inconsistency when building role map. Role " + roleName +
2228  " from db not found in the map.");
2229  }
2230  std::pair<std::string, std::string> roleVecElem(roleName, userName);
2231  granteeRooles.push_back(roleVecElem);
2232  }
2233 
2234  for (size_t i = 0; i < granteeRooles.size(); i++) {
2235  std::string roleName = granteeRooles[i].first;
2236  std::string granteeName = granteeRooles[i].second;
2237  auto* grantee = getGrantee(granteeName);
2238  if (!grantee) {
2239  throw runtime_error("Data inconsistency when building role map. Grantee " +
2240  granteeName + " not found in the map.");
2241  }
2242  if (granteeName == roleName) {
2243  continue;
2244  }
2245  Role* rl = dynamic_cast<Role*>(getGrantee(roleName));
2246  if (!rl) {
2247  throw runtime_error("Data inconsistency when building role map. Role " + roleName +
2248  " not found in the map.");
2249  }
2250  grantee->grantRole(rl);
2251  }
2252 }
2253 
2254 void SysCatalog::buildObjectDescriptorMap() {
2255  sys_write_lock write_lock(this);
2256  sys_sqlite_lock sqlite_lock(this);
2257  string objectQuery(
2258  "SELECT roleName, roleType, objectPermissionsType, dbId, objectId, "
2259  "objectPermissions, objectOwnerId, objectName "
2260  "from mapd_object_permissions");
2261  sqliteConnector_->query(objectQuery);
2262  size_t numRows = sqliteConnector_->getNumRows();
2263  for (size_t r = 0; r < numRows; ++r) {
2265  od->roleName = sqliteConnector_->getData<string>(r, 0);
2266  od->roleType = sqliteConnector_->getData<bool>(r, 1);
2267  od->objectType = sqliteConnector_->getData<int>(r, 2);
2268  od->dbId = sqliteConnector_->getData<int>(r, 3);
2269  od->objectId = sqliteConnector_->getData<int>(r, 4);
2270  od->privs.privileges = sqliteConnector_->getData<int>(r, 5);
2271  od->objectOwnerId = sqliteConnector_->getData<int>(r, 6);
2272  od->objectName = sqliteConnector_->getData<string>(r, 7);
2273  objectDescriptorMap_.insert(ObjectRoleDescriptorMap::value_type(
2274  std::to_string(od->dbId) + ":" + std::to_string(od->objectType) + ":" +
2275  std::to_string(od->objectId),
2276  od));
2277  }
2278 }
2279 
2280 template <typename F, typename... Args>
2281 void SysCatalog::execInTransaction(F&& f, Args&&... args) {
2282  sys_write_lock write_lock(this);
2283  sys_sqlite_lock sqlite_lock(this);
2284  sqliteConnector_->query("BEGIN TRANSACTION");
2285  try {
2286  (this->*f)(std::forward<Args>(args)...);
2287  } catch (std::exception&) {
2288  sqliteConnector_->query("ROLLBACK TRANSACTION");
2289  throw;
2290  }
2291  sqliteConnector_->query("END TRANSACTION");
2292 }
2293 
2294 void SysCatalog::createRole(const std::string& roleName, const bool& userPrivateRole) {
2295  execInTransaction(&SysCatalog::createRole_unsafe, roleName, userPrivateRole);
2296 }
2297 
2298 void SysCatalog::dropRole(const std::string& roleName) {
2299  execInTransaction(&SysCatalog::dropRole_unsafe, roleName);
2300 }
2301 
2302 void SysCatalog::grantRoleBatch(const std::vector<std::string>& roles,
2303  const std::vector<std::string>& grantees) {
2304  execInTransaction(&SysCatalog::grantRoleBatch_unsafe, roles, grantees);
2305 }
2306 
2307 void SysCatalog::grantRole(const std::string& role, const std::string& grantee) {
2308  execInTransaction(&SysCatalog::grantRole_unsafe, role, grantee);
2309 }
2310 
2311 void SysCatalog::revokeRoleBatch(const std::vector<std::string>& roles,
2312  const std::vector<std::string>& grantees) {
2313  execInTransaction(&SysCatalog::revokeRoleBatch_unsafe, roles, grantees);
2314 }
2315 
2316 void SysCatalog::revokeRole(const std::string& role, const std::string& grantee) {
2317  execInTransaction(&SysCatalog::revokeRole_unsafe, role, grantee);
2318 }
2319 
2320 void SysCatalog::grantDBObjectPrivileges(const string& grantee,
2321  const DBObject& object,
2322  const Catalog_Namespace::Catalog& catalog) {
2323  execInTransaction(
2324  &SysCatalog::grantDBObjectPrivileges_unsafe, grantee, object, catalog);
2325 }
2326 
2327 void SysCatalog::grantDBObjectPrivilegesBatch(const vector<string>& grantees,
2328  const vector<DBObject>& objects,
2329  const Catalog_Namespace::Catalog& catalog) {
2330  execInTransaction(
2331  &SysCatalog::grantDBObjectPrivilegesBatch_unsafe, grantees, objects, catalog);
2332 }
2333 
2334 void SysCatalog::revokeDBObjectPrivileges(const string& grantee,
2335  const DBObject& object,
2336  const Catalog_Namespace::Catalog& catalog) {
2337  execInTransaction(
2338  &SysCatalog::revokeDBObjectPrivileges_unsafe, grantee, object, catalog);
2339 }
2340 
2341 void SysCatalog::revokeDBObjectPrivilegesBatch(
2342  const vector<string>& grantees,
2343  const vector<DBObject>& objects,
2344  const Catalog_Namespace::Catalog& catalog) {
2345  execInTransaction(
2346  &SysCatalog::revokeDBObjectPrivilegesBatch_unsafe, grantees, objects, catalog);
2347 }
2348 
2349 void SysCatalog::revokeDBObjectPrivilegesFromAll(DBObject object, Catalog* catalog) {
2350  execInTransaction(&SysCatalog::revokeDBObjectPrivilegesFromAll_unsafe, object, catalog);
2351 }
2352 
2353 void SysCatalog::revokeDBObjectPrivilegesFromAllBatch(vector<DBObject>& objects,
2354  Catalog* catalog) {
2355  execInTransaction(
2356  &SysCatalog::revokeDBObjectPrivilegesFromAllBatch_unsafe, objects, catalog);
2357 }
2358 
2359 void SysCatalog::syncUserWithRemoteProvider(const std::string& user_name,
2360  std::vector<std::string> idp_roles,
2361  bool* is_super) {
2362  UserMetadata user_meta;
2363  bool is_super_user = is_super ? *is_super : false;
2364  // need to escalate to a write lock
2365  // need to unlock the read lock
2366  sys_read_lock read_lock(this);
2367  read_lock.unlock();
2368  sys_write_lock write_lock(this);
2369  if (!getMetadataForUser(user_name, user_meta)) {
2370  createUser(user_name, generate_random_string(72), is_super_user, "", true);
2371  LOG(INFO) << "User " << user_name << " has been created by remote identity provider"
2372  << " with IS_SUPER = " << (is_super_user ? "'TRUE'" : "'FALSE'");
2373  } else if (is_super && is_super_user != user_meta.isSuper) {
2374  alterUser(user_meta.userId, nullptr, is_super, nullptr, nullptr);
2375  LOG(INFO) << "IS_SUPER for user " << user_name << " has been changed to "
2376  << (is_super_user ? "TRUE" : "FALSE") << " by remote identity provider";
2377  }
2378  std::vector<std::string> current_roles = {};
2379  auto* user_rl = getUserGrantee(user_name);
2380  if (user_rl) {
2381  current_roles = user_rl->getRoles();
2382  }
2383  std::transform(
2384  current_roles.begin(), current_roles.end(), current_roles.begin(), to_upper);
2385  std::transform(idp_roles.begin(), idp_roles.end(), idp_roles.begin(), to_upper);
2386  std::list<std::string> roles_revoked, roles_granted;
2387  // first remove obsolete ones
2388  for (auto& current_role_name : current_roles) {
2389  if (std::find(idp_roles.begin(), idp_roles.end(), current_role_name) ==
2390  idp_roles.end()) {
2391  revokeRole(current_role_name, user_name);
2392  roles_revoked.push_back(current_role_name);
2393  }
2394  }
2395  for (auto& role_name : idp_roles) {
2396  if (std::find(current_roles.begin(), current_roles.end(), role_name) ==
2397  current_roles.end()) {
2398  auto* rl = getRoleGrantee(role_name);
2399  if (rl) {
2400  grantRole(role_name, user_name);
2401  roles_granted.push_back(role_name);
2402  } else {
2403  LOG(WARNING) << "Error synchronizing roles for user " << user_name << ": role "
2404  << role_name << " does not exist";
2405  }
2406  }
2407  }
2408  if (roles_granted.empty() && roles_revoked.empty()) {
2409  LOG(INFO) << "Roles for user " << user_name
2410  << " are up to date with remote identity provider";
2411  } else {
2412  if (!roles_revoked.empty()) {
2413  LOG(INFO) << "Roles revoked during synchronization with identity provider for user "
2414  << user_name << ": " << join(roles_revoked, " ");
2415  }
2416  if (!roles_granted.empty()) {
2417  LOG(INFO) << "Roles granted during synchronization with identity provider for user "
2418  << user_name << ": " << join(roles_granted, " ");
2419  }
2420  }
2421 }
2422 
2423 std::unordered_map<std::string, std::vector<std::string>>
2424 SysCatalog::getGranteesOfSharedDashboards(const std::vector<std::string>& dashboard_ids) {
2425  sys_sqlite_lock sqlite_lock(this);
2426  std::unordered_map<std::string, std::vector<std::string>> active_grantees;
2427  sqliteConnector_->query("BEGIN TRANSACTION");
2428  try {
2429  for (auto dash : dashboard_ids) {
2430  std::vector<std::string> grantees = {};
2431  sqliteConnector_->query_with_text_params(
2432  "SELECT roleName FROM mapd_object_permissions WHERE objectPermissions NOT IN "
2433  "(0,1) AND objectPermissionsType = ? AND objectId = ?",
2434  std::vector<std::string>{
2435  std::to_string(static_cast<int32_t>(DashboardDBObjectType)), dash});
2436  int num_rows = sqliteConnector_->getNumRows();
2437  if (num_rows == 0) {
2438  // no grantees
2439  continue;
2440  } else {
2441  for (size_t i = 0; i < sqliteConnector_->getNumRows(); ++i) {
2442  grantees.push_back(sqliteConnector_->getData<string>(i, 0));
2443  }
2444  active_grantees[dash] = grantees;
2445  }
2446  }
2447  } catch (const std::exception& e) {
2448  sqliteConnector_->query("ROLLBACK TRANSACTION");
2449  throw;
2450  }
2451  sqliteConnector_->query("END TRANSACTION");
2452  return active_grantees;
2453 }
2454 
2455 std::shared_ptr<Catalog> SysCatalog::getCatalog(const std::string& dbName) {
2456  dbid_to_cat_map::const_accessor cata;
2457  if (cat_map_.find(cata, dbName)) {
2458  return cata->second;
2459  } else {
2460  return nullptr;
2461  }
2462 }
2463 
2464 std::shared_ptr<Catalog> SysCatalog::getCatalog(const int32_t db_id) {
2465  dbid_to_cat_map::const_accessor cata;
2466  for (dbid_to_cat_map::iterator cat_it = cat_map_.begin(); cat_it != cat_map_.end();
2467  ++cat_it) {
2468  if (cat_it->second->getDatabaseId() == db_id) {
2469  return cat_it->second;
2470  }
2471  }
2472  return nullptr;
2473 }
2474 
2475 std::shared_ptr<Catalog> SysCatalog::getCatalog(
2476  const string& basePath,
2477  const DBMetadata& curDB,
2478  std::shared_ptr<Data_Namespace::DataMgr> dataMgr,
2479  const std::vector<LeafHostInfo>& string_dict_hosts,
2480  std::shared_ptr<Calcite> calcite,
2481  bool is_new_db) {
2482  auto cat = getCatalog(curDB.dbName);
2483  if (cat) {
2484  return cat;
2485  }
2486 
2487  // Catalog doesnt exist
2488  // has to be made outside of lock as migration uses cat
2489  cat = std::make_shared<Catalog>(
2490  basePath, curDB, dataMgr, string_dict_hosts, calcite, is_new_db);
2491 
2492  dbid_to_cat_map::accessor cata;
2493 
2494  if (cat_map_.find(cata, curDB.dbName)) {
2495  return cata->second;
2496  }
2497 
2498  cat_map_.insert(cata, curDB.dbName);
2499  cata->second = cat;
2500 
2501  return cat;
2502 }
2503 
2504 void SysCatalog::removeCatalog(const std::string& dbName) {
2505  cat_map_.erase(dbName);
2506 }
2507 
2508 } // namespace Catalog_Namespace
static const AccessPrivileges VIEW_SQL_EDITOR
Definition: DBObject.h:153
std::string cat(Ts &&...args)
DBObjectKey getObjectKey() const
Definition: DBObject.h:211
class for a per-database catalog. also includes metadata for the current database and the current use...
Definition: Catalog.h:101
static const AccessPrivileges ALL_DATABASE
Definition: DBObject.h:152
DBObjectType
Definition: DBObject.h:42
void updatePrivileges(const DBObject &object)
Definition: DBObject.cpp:141
static const AccessPrivileges ALL_TABLE_MIGRATE
Definition: DBObject.h:157
#define LOG(tag)
Definition: Logger.h:188
static const int32_t ALL
Definition: DBObject.h:79
std::string join(T const &container, std::string const &delim)
specifies the object_roles content in-memory of a row in mapd_object_permissions table ...
#define UNREACHABLE()
Definition: Logger.h:241
void setObjectKey(const DBObjectKey &objectKey)
Definition: DBObject.h:215
const std::string OMNISCI_SYSTEM_CATALOG
Definition: SysCatalog.h:57
Definition: Grantee.h:70
int32_t objectId
Definition: DBObject.h:57
void setName(std::string name)
Definition: DBObject.h:208
Definition: Grantee.h:76
void setPrivileges(const AccessPrivileges &privs)
Definition: DBObject.h:217
std::string to_string(char const *&&v)
static const AccessPrivileges ALL_VIEW
Definition: DBObject.h:178
This file contains the class specification and related data structures for Catalog.
static DBObjectKey fromString(const std::vector< std::string > &key, const DBObjectType &type)
Definition: DBObject.cpp:259
This file contains the class specification and related data structures for SysCatalog.
bool g_enable_s3_fsi
Definition: Catalog.cpp:93
static bool parseUserMetadataFromSQLite(const std::unique_ptr< SqliteConnector > &conn, UserMetadata &user)
void setPermissionType(const DBObjectType &permissionType)
Definition: DBObject.cpp:149
const DBMetadata & getCurrentDB() const
Definition: Catalog.h:221
void init(LogOptions const &log_opts)
Definition: Logger.cpp:280
const std::string OMNISCI_DEFAULT_DB
Definition: SysCatalog.h:58
std::string generate_random_string(const size_t len)
virtual void revokeAllOnDatabase(int32_t dbId)
Definition: Grantee.cpp:279
std::string hash_with_bcrypt(const std::string &pwd)
Definition: SysCatalog.cpp:66
static const int32_t MAPD_VERSION
Definition: release.h:33
static const AccessPrivileges ALL_DASHBOARD_MIGRATE
Definition: DBObject.h:169
static const AccessPrivileges ALL_SERVER
Definition: DBObject.h:188
static const AccessPrivileges NONE
Definition: DBObject.h:149
static const std::string SYSTEM_ROLE_TAG("#dash_system_role")
specifies the content in-memory of a row in the dashboard
std::string to_upper(const std::string &str)
void loadKey()
Definition: DBObject.cpp:179
void setObjectType(const DBObjectType &objectType)
Definition: DBObject.cpp:152
const std::string OMNISCI_ROOT_USER
Definition: SysCatalog.h:59
static const AccessPrivileges ALL_VIEW_MIGRATE
Definition: DBObject.h:177
const std::string OMNISCI_ROOT_PASSWD_DEFAULT
Definition: SysCatalog.h:62
const int OMNISCI_ROOT_USER_ID
Definition: SysCatalog.h:60
int32_t dbId
Definition: DBObject.h:56
static const AccessPrivileges ALL_DASHBOARD
Definition: DBObject.h:170
static const AccessPrivileges ACCESS
Definition: DBObject.h:154
static const AccessPrivileges ALL_TABLE
Definition: DBObject.h:158
const std::string OMNISCI_ROOT_USER_ID_STR
Definition: SysCatalog.h:61
mapd_shared_lock< mapd_shared_mutex > read_lock
void insertOrUpdateObjectPrivileges(std::unique_ptr< SqliteConnector > &sqliteConnector, std::string roleName, bool userRole, DBObject &object)
Definition: SysCatalog.cpp:351
auto get_users(std::unique_ptr< SqliteConnector > &sqliteConnector, const int32_t dbId=-1)
#define CHECK(condition)
Definition: Logger.h:197
std::list< DBSummary > DBSummaryList
Definition: SysCatalog.h:123
int32_t permissionType
Definition: DBObject.h:55
void deleteObjectPrivileges(std::unique_ptr< SqliteConnector > &sqliteConnector, std::string roleName, bool userRole, DBObject &object)
Definition: SysCatalog.cpp:332
mapd_unique_lock< mapd_shared_mutex > write_lock
int64_t privileges
Definition: DBObject.h:134
string name
Definition: setup.py:44
read_lock< SysCatalog > sys_read_lock
Definition: Catalog.cpp:112
bool g_enable_fsi
Definition: Catalog.cpp:92
std::string userLoggable() const
Definition: SysCatalog.cpp:85
DEVICE void swap(ARGS &&...args)
Definition: gpu_enabled.h:114
virtual void renameDbObject(const DBObject &object)
Definition: Grantee.cpp:108
std::atomic< bool > isSuper
Definition: SysCatalog.h:96