LCOV - code coverage report
Current view: top level - sql/server - sql_privileges.c (source / functions) Hit Total Coverage
Test: coverage.info Lines: 574 680 84.4 %
Date: 2024-12-20 21:24:02 Functions: 34 36 94.4 %

          Line data    Source code
       1             : /*
       2             :  * SPDX-License-Identifier: MPL-2.0
       3             :  *
       4             :  * This Source Code Form is subject to the terms of the Mozilla Public
       5             :  * License, v. 2.0.  If a copy of the MPL was not distributed with this
       6             :  * file, You can obtain one at http://mozilla.org/MPL/2.0/.
       7             :  *
       8             :  * Copyright 2024 MonetDB Foundation;
       9             :  * Copyright August 2008 - 2023 MonetDB B.V.;
      10             :  * Copyright 1997 - July 2008 CWI.
      11             :  */
      12             : 
      13             : /*
      14             :  * Privileges
      15             :  * ==========
      16             :  *
      17             :  * Sql has a simple access control schema. There are two types of authorization,
      18             :  * users and roles. Each user may be part of several roles.
      19             :  * For each authorization identity a set of privileges is administrated.
      20             :  * These are administrated on multiple levels where lower levels (ie.
      21             :  * table or column level) overwrite privileges on higher levels.
      22             :  *
      23             :  */
      24             : 
      25             : #include "monetdb_config.h"
      26             : #include "sql_privileges.h"
      27             : #include "sql_storage.h"
      28             : #include "sql_semantic.h"
      29             : #include "sql_parser.h"
      30             : #include "mal_exception.h"
      31             : 
      32             : #define PRIV_ROLE_ADMIN 0
      33             : 
      34             : #define GLOBAL_OBJID 0
      35             : 
      36             : static const char *
      37           0 : priv2string(int priv)
      38             : {
      39           0 :         switch (priv) {
      40             :         case PRIV_SELECT:
      41             :                 return "SELECT";
      42           0 :         case PRIV_UPDATE:
      43           0 :                 return "UPDATE";
      44           0 :         case PRIV_INSERT:
      45           0 :                 return "INSERT";
      46           0 :         case PRIV_DELETE:
      47           0 :                 return "DELETE";
      48           0 :         case PRIV_TRUNCATE:
      49           0 :                 return "TRUNCATE";
      50           0 :         case PRIV_EXECUTE:
      51           0 :                 return "EXECUTE";
      52             :         }
      53           0 :         return "UNKNOWN PRIV";
      54             : }
      55             : 
      56             : static int
      57      118634 : sql_insert_priv(mvc *sql, sqlid auth_id, sqlid obj_id, int privilege, sqlid grantor, int grantable)
      58             : {
      59      118634 :         sql_schema *ss = mvc_bind_schema(sql, "sys");
      60      118634 :         sql_table *pt = find_sql_table(sql->session->tr, ss, "privileges");
      61      118634 :         sqlstore *store = sql->session->tr->store;
      62             : 
      63      118634 :         return store->table_api.table_insert(sql->session->tr, pt, &obj_id, &auth_id, &privilege, &grantor, &grantable);
      64             : }
      65             : 
      66             : static int
      67           5 : sql_insert_all_privs(mvc *sql, sqlid auth_id, sqlid obj_id, int grantor, int grantable)
      68             : {
      69           5 :         int log_res = 0;
      70             : 
      71           5 :         if ((log_res = sql_insert_priv(sql, auth_id, obj_id, PRIV_SELECT, grantor, grantable)) ||
      72           5 :                 (log_res = sql_insert_priv(sql, auth_id, obj_id, PRIV_UPDATE, grantor, grantable)) ||
      73           5 :                 (log_res = sql_insert_priv(sql, auth_id, obj_id, PRIV_INSERT, grantor, grantable)) ||
      74           5 :                 (log_res = sql_insert_priv(sql, auth_id, obj_id, PRIV_DELETE, grantor, grantable)) ||
      75           5 :                 (log_res = sql_insert_priv(sql, auth_id, obj_id, PRIV_TRUNCATE, grantor, grantable)))
      76           0 :                 return log_res;
      77             :         return 0;
      78             : }
      79             : 
      80             : static bool
      81     1215575 : admin_privs(sqlid grantor)
      82             : {
      83     1215575 :         if (grantor == USER_MONETDB || grantor == ROLE_SYSADMIN) {
      84          26 :                 return true;
      85             :         }
      86             :         return false;
      87             : }
      88             : 
      89             : int
      90      332664 : mvc_schema_privs(mvc *m, sql_schema *s)
      91             : {
      92      332664 :         if (admin_privs(m->user_id) || admin_privs(m->role_id))
      93             :                 return 1;
      94        2401 :         if (!s)
      95             :                 return 0;
      96        2401 :         if (m->user_id == s->auth_id || m->role_id == s->auth_id)
      97        2383 :                 return 1;
      98             :         return 0;
      99             : }
     100             : 
     101             : static bool
     102      118626 : schema_privs(sqlid grantor, sql_schema *s)
     103             : {
     104      337233 :         if (admin_privs(grantor))
     105             :                 return true;
     106           8 :         if (!s)
     107             :                 return false;
     108           8 :         if (grantor == s->auth_id)
     109             :                 return true;
     110             :         return false;
     111             : }
     112             : 
     113             : str
     114          10 : sql_grant_global_privs( mvc *sql, char *grantee, int privs, int grant, sqlid grantor)
     115             : {
     116          10 :         bool allowed;
     117          10 :         sqlid grantee_id;
     118          10 :         int log_res;
     119             : 
     120          10 :         allowed = admin_privs(grantor);
     121             : 
     122           0 :         if (!allowed)
     123           0 :                 allowed = sql_grantable(sql, grantor, GLOBAL_OBJID, privs) == 1;
     124             : 
     125           0 :         if (!allowed)
     126           0 :                 throw(SQL,"sql.grant_global",SQLSTATE(01007) "GRANT: Grantor '%s' is not allowed to grant global privileges", get_string_global_var(sql, "current_user"));
     127             : 
     128          10 :         grantee_id = sql_find_auth(sql, grantee);
     129          10 :         if (grantee_id <= 0)
     130           2 :                 throw(SQL,"sql.grant_global",SQLSTATE(01007) "GRANT: User/role '%s' unknown", grantee);
     131             :         /* first check if privilege isn't already given */
     132           8 :         if ((sql_privilege(sql, grantee_id, GLOBAL_OBJID, privs) >= 0))
     133           0 :                 throw(SQL,"sql.grant_global",SQLSTATE(01007) "GRANT: User/role '%s' already has this privilege", grantee);
     134           8 :         if ((log_res = sql_insert_priv(sql, grantee_id, GLOBAL_OBJID, privs, grantor, grant)))
     135           0 :                 throw(SQL,"sql.grant_global",SQLSTATE(42000) "GRANT: failed%s", log_res == LOG_CONFLICT ? " due to conflict with another transaction" : "");
     136             : 
     137             :         /* Add dependencies created */
     138           8 :         if ((log_res = sql_trans_add_dependency(sql->session->tr, grantee_id, ddl)) != LOG_OK)
     139           0 :                 throw(SQL, "sql.grant_table", SQLSTATE(HY013) MAL_MALLOC_FAIL);
     140           8 :         if ((log_res = sql_trans_add_dependency(sql->session->tr, grantor, ddl)) != LOG_OK)
     141           0 :                 throw(SQL, "sql.grant_table", SQLSTATE(HY013) MAL_MALLOC_FAIL);
     142             :         return MAL_SUCCEED;
     143             : }
     144             : 
     145             : char *
     146       18653 : sql_grant_table_privs( mvc *sql, char *grantee, int privs, char *sname, char *tname, char *cname, int grant, sqlid grantor)
     147             : {
     148       18653 :         sql_table *t = NULL;
     149       18653 :         sql_column *c = NULL;
     150       18653 :         bool allowed;
     151       18653 :         sqlid grantee_id;
     152       18653 :         int all = PRIV_SELECT | PRIV_UPDATE | PRIV_INSERT | PRIV_DELETE | PRIV_TRUNCATE, log_res;
     153             : 
     154       18653 :         if (!(t = find_table_or_view_on_scope(sql, NULL, sname, tname, "GRANT", false)))
     155           0 :                 throw(SQL,"sql.grant_table", "%s", sql->errstr);
     156       18653 :         if (isDeclaredTable(t))
     157           0 :                 throw(SQL,"sql.grant_table", SQLSTATE(42000) "GRANT: cannot grant on a declared table");
     158             : 
     159       18653 :         allowed = schema_privs(grantor, t->s);
     160             : 
     161       18653 :         if (!cname) {
     162       18597 :                 if (!allowed)
     163           7 :                         allowed = sql_grantable(sql, grantor, t->base.id, privs) == 1;
     164             : 
     165           7 :                 if (!allowed)
     166           2 :                         throw(SQL,"sql.grant_table", SQLSTATE(01007) "GRANT: Grantor '%s' is not allowed to grant privileges for table '%s'", get_string_global_var(sql, "current_user"), tname);
     167             :         }
     168          56 :         if (cname) {
     169          56 :                 c = mvc_bind_column(sql, t, cname);
     170          56 :                 if (!c)
     171           1 :                         throw(SQL,"sql.grant_table",SQLSTATE(42S22) "GRANT: Table '%s' has no column '%s'", tname, cname);
     172             :                 /* allowed on column */
     173          55 :                 if (!allowed)
     174           0 :                         allowed = sql_grantable(sql, grantor, c->base.id, privs) == 1;
     175             : 
     176           0 :                 if (!allowed)
     177           0 :                         throw(SQL, "sql.grant_table", SQLSTATE(01007) "GRANT: Grantor '%s' is not allowed to grant privilege %s for table '%s'", get_string_global_var(sql, "current_user"), priv2string(privs), tname);
     178             :         }
     179             : 
     180       18650 :         grantee_id = sql_find_auth(sql, grantee);
     181       18650 :         if (grantee_id <= 0)
     182           1 :                 throw(SQL,"sql.grant_table", SQLSTATE(01007) "GRANT: User/role '%s' unknown", grantee);
     183             :         /* first check if privilege isn't already given */
     184       18654 :         if ((privs == all &&
     185          10 :             (sql_privilege(sql, grantee_id, t->base.id, PRIV_SELECT) >= 0 ||
     186          10 :              sql_privilege(sql, grantee_id, t->base.id, PRIV_UPDATE) >= 0 ||
     187          10 :              sql_privilege(sql, grantee_id, t->base.id, PRIV_INSERT) >= 0 ||
     188          10 :              sql_privilege(sql, grantee_id, t->base.id, PRIV_DELETE) >= 0 ||
     189           5 :              sql_privilege(sql, grantee_id, t->base.id, PRIV_TRUNCATE) >= 0)) ||
     190       18649 :             (privs != all && !c && sql_privilege(sql, grantee_id, t->base.id, privs) >= 0) ||
     191       18647 :             (privs != all && c && sql_privilege(sql, grantee_id, c->base.id, privs) >= 0)) {
     192           2 :                 throw(SQL, "sql.grant_table", SQLSTATE(01007) "GRANT: User/role '%s' already has this privilege", grantee);
     193             :         }
     194       18647 :         if (privs == all) {
     195           5 :                 if ((log_res = sql_insert_all_privs(sql, grantee_id, t->base.id, grantor, grant)))
     196           0 :                         throw(SQL, "sql.grant_table", SQLSTATE(42000) "GRANT: failed%s", log_res == LOG_CONFLICT ? " due to conflict with another transaction" : "");
     197       18642 :         } else if (!c) {
     198       18587 :                 if ((log_res = sql_insert_priv(sql, grantee_id, t->base.id, privs, grantor, grant)))
     199           0 :                         throw(SQL, "sql.grant_table", SQLSTATE(42000) "GRANT: failed%s", log_res == LOG_CONFLICT ? " due to conflict with another transaction" : "");
     200             :         } else {
     201          55 :                 if ((log_res = sql_insert_priv(sql, grantee_id, c->base.id, privs, grantor, grant)))
     202           0 :                         throw(SQL, "sql.grant_table", SQLSTATE(42000) "GRANT: failed%s", log_res == LOG_CONFLICT ? " due to conflict with another transaction" : "");
     203             :         }
     204             : 
     205             :         /* Add dependencies created */
     206       18647 :         if (privs == all || !c) {
     207       18592 :                 if (!isNew(t) && (log_res = sql_trans_add_dependency(sql->session->tr, t->base.id, ddl)) != LOG_OK)
     208           0 :                         throw(SQL, "sql.grant_table", SQLSTATE(HY013) MAL_MALLOC_FAIL);
     209             :         } else {
     210          55 :                 if (!isNew(c) && (log_res = sql_trans_add_dependency(sql->session->tr, c->base.id, ddl)) != LOG_OK)
     211           0 :                         throw(SQL, "sql.grant_table", SQLSTATE(HY013) MAL_MALLOC_FAIL);
     212             :         }
     213       18647 :         if ((log_res = sql_trans_add_dependency(sql->session->tr, grantee_id, ddl)) != LOG_OK)
     214           0 :                 throw(SQL, "sql.grant_table", SQLSTATE(HY013) MAL_MALLOC_FAIL);
     215       18647 :         if ((log_res = sql_trans_add_dependency(sql->session->tr, grantor, ddl)) != LOG_OK)
     216           0 :                 throw(SQL, "sql.grant_table", SQLSTATE(HY013) MAL_MALLOC_FAIL);
     217             : 
     218             :         return NULL;
     219             : }
     220             : 
     221             : char *
     222       99959 : sql_grant_func_privs( mvc *sql, char *grantee, int privs, char *sname, sqlid func_id, int grant, sqlid grantor)
     223             : {
     224       99959 :         sql_schema *s = NULL;
     225       99959 :         bool allowed;
     226       99959 :         sqlid grantee_id;
     227       99959 :         int log_res;
     228             : 
     229       99959 :         assert(sname);
     230       99959 :         if (!(s = mvc_bind_schema(sql, sname)))
     231           0 :                 throw(SQL,"sql.grant_func",SQLSTATE(3F000) "GRANT: no such schema '%s'", sname);
     232       99959 :         sql_base *b = os_find_id(s->funcs, sql->session->tr, func_id);
     233       99959 :         sql_func *f = (sql_func*)b;
     234       99959 :         assert(f);
     235       99959 :         allowed = schema_privs(grantor, f->s);
     236             : 
     237             :         if (!allowed)
     238           0 :                 allowed = sql_grantable(sql, grantor, f->base.id, privs) == 1;
     239             : 
     240       99959 :         if (!allowed)
     241           0 :                 throw(SQL, "sql.grant_func", SQLSTATE(01007) "GRANT: Grantor '%s' is not allowed to grant privileges for function '%s'", get_string_global_var(sql, "current_user"), f->base.name);
     242             : 
     243       99959 :         grantee_id = sql_find_auth(sql, grantee);
     244       99959 :         if (grantee_id <= 0)
     245           0 :                 throw(SQL, "sql.grant_func", SQLSTATE(01007) "GRANT: User/role '%s' unknown", grantee);
     246             :         /* first check if privilege isn't already given */
     247       99959 :         if (sql_privilege(sql, grantee_id, f->base.id, privs) >= 0)
     248           0 :                 throw(SQL,"sql.grant_func", SQLSTATE(01007) "GRANT: User/role '%s' already has this privilege", grantee);
     249       99959 :         if ((log_res = sql_insert_priv(sql, grantee_id, f->base.id, privs, grantor, grant)))
     250           0 :                 throw(SQL,"sql.grant_func", SQLSTATE(42000) "GRANT: failed%s", log_res == LOG_CONFLICT ? " due to conflict with another transaction" : "");
     251             : 
     252             :         /* Add dependencies created */
     253       99959 :         if (!isNew(f) && (log_res = sql_trans_add_dependency(sql->session->tr, func_id, ddl)) != LOG_OK)
     254           0 :                 throw(SQL, "sql.grant_func", SQLSTATE(HY013) MAL_MALLOC_FAIL);
     255       99959 :         if ((log_res = sql_trans_add_dependency(sql->session->tr, grantor, ddl)) != LOG_OK)
     256           0 :                 throw(SQL, "sql.grant_func", SQLSTATE(HY013) MAL_MALLOC_FAIL);
     257             :         return NULL;
     258             : }
     259             : 
     260             : static char *
     261          16 : sql_delete_priv(mvc *sql, sqlid auth_id, sqlid obj_id, int privilege, sqlid grantor, int grantable, const char *op, const char *call)
     262             : {
     263          16 :         sql_schema *ss = mvc_bind_schema(sql, "sys");
     264          16 :         sql_table *privs = find_sql_table(sql->session->tr, ss, "privileges");
     265          16 :         sql_column *priv_obj = find_sql_column(privs, "obj_id");
     266          16 :         sql_column *priv_auth = find_sql_column(privs, "auth_id");
     267          16 :         sql_column *priv_priv = find_sql_column(privs, "privileges");
     268          16 :         sql_trans *tr = sql->session->tr;
     269          16 :         sqlstore *store = tr->store;
     270          16 :         rids *A;
     271          16 :         oid rid = oid_nil;
     272          16 :         int log_res = LOG_OK;
     273             : 
     274          16 :         (void) grantor;
     275          16 :         (void) grantable;
     276             : 
     277             :         /* select privileges of this auth_id, privilege, obj_id */
     278          16 :         A = store->table_api.rids_select(tr, priv_auth, &auth_id, &auth_id, priv_priv, &privilege, &privilege, priv_obj, &obj_id, &obj_id, NULL );
     279          16 :         if (!A)
     280           0 :                 throw(SQL, "sql.delete_prive", SQLSTATE(HY013) MAL_MALLOC_FAIL);
     281             :         /* remove them */
     282          32 :         for(rid = store->table_api.rids_next(A); !is_oid_nil(rid) && log_res == LOG_OK; rid = store->table_api.rids_next(A))
     283          16 :                 log_res = store->table_api.table_delete(tr, privs, rid);
     284          16 :         store->table_api.rids_destroy(A);
     285          16 :         if (log_res != LOG_OK)
     286           0 :                 throw(SQL, op, SQLSTATE(42000) "%s: failed%s", call, log_res == LOG_CONFLICT ? " due to conflict with another transaction" : "");
     287             :         return NULL;
     288             : }
     289             : 
     290             : char *
     291           2 : sql_revoke_global_privs( mvc *sql, char *grantee, int privs, int grant, sqlid grantor)
     292             : {
     293           2 :         bool allowed;
     294           2 :         sqlid grantee_id;
     295             : 
     296           2 :         allowed = admin_privs(grantor);
     297             : 
     298           0 :         if (!allowed)
     299           0 :                 allowed = sql_grantable(sql, grantor, GLOBAL_OBJID, privs) == 1;
     300             : 
     301           0 :         if (!allowed)
     302           0 :                 throw(SQL, "sql.revoke_global", SQLSTATE(01006) "REVOKE: Grantor '%s' is not allowed to revoke global privileges", get_string_global_var(sql, "current_user"));
     303             : 
     304           2 :         grantee_id = sql_find_auth(sql, grantee);
     305           2 :         if (grantee_id <= 0)
     306           0 :                 throw(SQL, "sql.revoke_global", SQLSTATE(01006) "REVOKE: User/role '%s' unknown", grantee);
     307           2 :         return sql_delete_priv(sql, grantee_id, GLOBAL_OBJID, privs, grantor, grant, "sql.revoke_global", "REVOKE");
     308             : }
     309             : 
     310             : char *
     311          13 : sql_revoke_table_privs( mvc *sql, char *grantee, int privs, char *sname, char *tname, char *cname, int grant, sqlid grantor)
     312             : {
     313          13 :         sql_table *t = NULL;
     314          13 :         sql_column *c = NULL;
     315          13 :         bool allowed;
     316          13 :         sqlid grantee_id;
     317          13 :         int all = PRIV_SELECT | PRIV_UPDATE | PRIV_INSERT | PRIV_DELETE | PRIV_TRUNCATE;
     318          13 :         char *msg = NULL;
     319             : 
     320          13 :         if (!(t = find_table_or_view_on_scope(sql, NULL, sname, tname, "REVOKE", false)))
     321           0 :                 throw(SQL,"sql.revoke_table","%s", sql->errstr);
     322          13 :         if (isDeclaredTable(t))
     323           0 :                 throw(SQL,"sql.revoke_table", SQLSTATE(42000) "REVOKE: cannot revoke on a declared table");
     324             : 
     325          13 :         allowed = schema_privs(grantor, t->s);
     326             :         if (!allowed)
     327           0 :                 allowed = sql_grantable(sql, grantor, t->base.id, privs) == 1;
     328             : 
     329          13 :         if (!allowed)
     330           0 :                 throw(SQL, "sql.revoke_table", SQLSTATE(01006) "REVOKE: Grantor '%s' is not allowed to revoke privileges for table '%s'", get_string_global_var(sql, "current_user"), tname);
     331             : 
     332          13 :         if (cname) {
     333           2 :                 c = mvc_bind_column(sql, t, cname);
     334           2 :                 if (!c)
     335           0 :                         throw(SQL,"sql.revoke_table", SQLSTATE(42S22) "REVOKE: table '%s' has no column '%s'", tname, cname);
     336             :                 /* allowed on column */
     337             :                 if (!allowed)
     338             :                         allowed = sql_grantable(sql, grantor, c->base.id, privs) == 1;
     339             : 
     340             :                 if (!allowed)
     341             :                         throw(SQL, "sql.revoke_table", SQLSTATE(01006) "REVOKE: Grantor '%s' is not allowed to revoke privilege %s for table '%s'", get_string_global_var(sql, "current_user"), priv2string(privs), tname);
     342             :         }
     343             : 
     344          13 :         grantee_id = sql_find_auth(sql, grantee);
     345          13 :         if (grantee_id <= 0)
     346           0 :                  throw(SQL,"sql.revoke_table", SQLSTATE(01006) "REVOKE: User/role '%s' unknown", grantee);
     347          13 :         if (privs == all) {
     348           0 :                 if ((msg = sql_delete_priv(sql, grantee_id, t->base.id, PRIV_SELECT, grantor, grant, "sql.revoke_table", "REVOKE")) ||
     349           0 :                         (msg = sql_delete_priv(sql, grantee_id, t->base.id, PRIV_UPDATE, grantor, grant, "sql.revoke_table", "REVOKE")) ||
     350           0 :                         (msg = sql_delete_priv(sql, grantee_id, t->base.id, PRIV_INSERT, grantor, grant, "sql.revoke_table", "REVOKE")) ||
     351           0 :                         (msg = sql_delete_priv(sql, grantee_id, t->base.id, PRIV_DELETE, grantor, grant, "sql.revoke_table", "REVOKE")) ||
     352           0 :                         (msg = sql_delete_priv(sql, grantee_id, t->base.id, PRIV_TRUNCATE, grantor, grant, "sql.revoke_table", "REVOKE")))
     353           0 :                         return msg;
     354          13 :         } else if (!c) {
     355          11 :                 msg = sql_delete_priv(sql, grantee_id, t->base.id, privs, grantor, grant, "sql.revoke_table", "REVOKE");
     356             :         } else {
     357           2 :                 msg = sql_delete_priv(sql, grantee_id, c->base.id, privs, grantor, grant, "sql.revoke_table", "REVOKE");
     358             :         }
     359             :         return msg;
     360             : }
     361             : 
     362             : char *
     363           1 : sql_revoke_func_privs( mvc *sql, char *grantee, int privs, char *sname, sqlid func_id, int grant, sqlid grantor)
     364             : {
     365           1 :         sql_schema *s = NULL;
     366           1 :         bool allowed;
     367           1 :         sqlid grantee_id;
     368             : 
     369           1 :         assert(sname);
     370           1 :         if (!(s = mvc_bind_schema(sql, sname)))
     371           0 :                 throw(SQL,"sql.revoke_func", SQLSTATE(3F000) "REVOKE: no such schema '%s'", sname);
     372           1 :         sql_base *b = os_find_id(s->funcs, sql->session->tr, func_id);
     373           1 :         sql_func *f = (sql_func*)b;
     374           1 :         assert(f);
     375           1 :         allowed = schema_privs(grantor, f->s);
     376             :         if (!allowed)
     377           0 :                 allowed = sql_grantable(sql, grantor, f->base.id, privs) == 1;
     378             : 
     379           1 :         if (!allowed)
     380           0 :                 throw(SQL, "sql.revoke_func", SQLSTATE(01006) "REVOKE: Grantor '%s' is not allowed to revoke privileges for function '%s'", get_string_global_var(sql, "current_user"), f->base.name);
     381             : 
     382           1 :         grantee_id = sql_find_auth(sql, grantee);
     383           1 :         if (grantee_id <= 0)
     384           0 :                 throw(SQL, "sql.revoke_func", SQLSTATE(01006) "REVOKE: User/role '%s' unknown", grantee);
     385           1 :         return sql_delete_priv(sql, grantee_id, f->base.id, privs, grantor, grant, "sql.revoke_func", "REVOKE");
     386             : }
     387             : 
     388             : static bool
     389         678 : sql_create_auth_id(mvc *m, sqlid id, str auth)
     390             : {
     391         678 :         int grantor = 0; /* no grantor */
     392         678 :         sql_schema *sys = find_sql_schema(m->session->tr, "sys");
     393         678 :         sql_table *auths = find_sql_table(m->session->tr, sys, "auths");
     394         678 :         sql_column *auth_name = find_sql_column(auths, "name");
     395         678 :         sqlstore *store = m->session->tr->store;
     396         678 :         int log_res = LOG_OK;
     397             : 
     398         678 :         if (!is_oid_nil(store->table_api.column_find_row(m->session->tr, auth_name, auth, NULL)))
     399             :                 return false;
     400             : 
     401         678 :         if ((log_res = store->table_api.table_insert(m->session->tr, auths, &id, &auth, &grantor)) != LOG_OK) {
     402           0 :                 (void)createException(SQL, "sql.create_auth_id", SQLSTATE(42000) "CREATE AUTH: failed%s", log_res == LOG_CONFLICT ? " due to conflict with another transaction" : "");
     403           0 :                 return false;
     404             :         }
     405             :         return true;
     406             : }
     407             : 
     408             : str
     409          26 : sql_create_role(mvc *m, str auth, sqlid grantor)
     410             : {
     411          26 :         sqlid id;
     412          26 :         sql_trans *tr = m->session->tr;
     413          26 :         sqlstore *store = m->session->tr->store;
     414          26 :         sql_schema *sys = find_sql_schema(tr, "sys");
     415          26 :         sql_table *auths = find_sql_table(tr, sys, "auths");
     416          26 :         sql_column *auth_name = find_sql_column(auths, "name");
     417          26 :         int log_res = LOG_OK;
     418             : 
     419          26 :         if (!admin_privs(grantor))
     420           0 :                 throw(SQL, "sql.create_role", SQLSTATE(0P000) "Insufficient privileges to create role '%s'", auth);
     421          26 :         if (!is_oid_nil(store->table_api.column_find_row(tr, auth_name, auth, NULL)))
     422           1 :                 throw(SQL, "sql.create_role", SQLSTATE(0P000) "Role '%s' already exists", auth);
     423             : 
     424          25 :         id = store_next_oid(tr->store);
     425          25 :         if ((log_res = store->table_api.table_insert(tr, auths, &id, &auth, &grantor)) != LOG_OK)
     426           1 :                 throw(SQL, "sql.create_role", SQLSTATE(42000) "CREATE ROLE: failed%s", log_res == LOG_CONFLICT ? " due to conflict with another transaction" : "");
     427             :         return NULL;
     428             : }
     429             : 
     430             : str
     431          19 : sql_drop_role(mvc *m, str auth)
     432             : {
     433          19 :         sqlid role_id = sql_find_auth(m, auth);
     434          19 :         sql_schema *sys = find_sql_schema(m->session->tr, "sys");
     435          19 :         sql_table *auths = find_sql_table(m->session->tr, sys, "auths");
     436          19 :         sql_table *user_roles = find_sql_table(m->session->tr, sys, "user_role");
     437          19 :         sql_trans *tr = m->session->tr;
     438          19 :         sqlstore *store = m->session->tr->store;
     439          19 :         rids *A;
     440          19 :         oid rid;
     441          19 :         int log_res = LOG_OK;
     442             : 
     443          19 :         rid = store->table_api.column_find_row(tr, find_sql_column(auths, "name"), auth, NULL);
     444          19 :         if (is_oid_nil(rid))
     445           1 :                 throw(SQL, "sql.drop_role", SQLSTATE(0P000) "DROP ROLE: no such role '%s'", auth);
     446          18 :         if ((log_res = store->table_api.table_delete(m->session->tr, auths, rid)) != LOG_OK)
     447           0 :                 throw(SQL, "sql.drop_role", SQLSTATE(42000) "DROP ROLE: failed%s", log_res == LOG_CONFLICT ? " due to conflict with another transaction" : "");
     448             : 
     449             :         /* select user roles of this role_id */
     450          18 :         A = store->table_api.rids_select(tr, find_sql_column(user_roles, "role_id"), &role_id, &role_id, NULL);
     451          18 :         if (!A)
     452           0 :                 throw(SQL, "sql.drop_role", SQLSTATE(HY013) MAL_MALLOC_FAIL);
     453             :         /* remove them */
     454          19 :         for(rid = store->table_api.rids_next(A); !is_oid_nil(rid) && log_res == LOG_OK; rid = store->table_api.rids_next(A))
     455           1 :                 log_res = store->table_api.table_delete(tr, user_roles, rid);
     456          18 :         store->table_api.rids_destroy(A);
     457          18 :         if (log_res != LOG_OK)
     458           0 :                 throw(SQL, "sql.drop_role", SQLSTATE(42000) "DROP ROLE: failed%s", log_res == LOG_CONFLICT ? " due to conflict with another transaction" : "");
     459             : 
     460             :         /* Flag as removed */
     461          18 :         if ((log_res = sql_trans_add_dependency_change(tr, role_id, ddl)) != LOG_OK)
     462           0 :                 throw(SQL, "sql.drop_role", SQLSTATE(HY013) MAL_MALLOC_FAIL);
     463             :         return NULL;
     464             : }
     465             : 
     466             : static oid
     467      123515 : sql_privilege_rid(mvc *m, sqlid auth_id, sqlid obj_id, int priv)
     468             : {
     469      123515 :         sql_schema *sys = find_sql_schema(m->session->tr, "sys");
     470      123515 :         sql_table *privs = find_sql_table(m->session->tr, sys, "privileges");
     471      123515 :         sql_column *priv_obj = find_sql_column(privs, "obj_id");
     472      123515 :         sql_column *priv_auth = find_sql_column(privs, "auth_id");
     473      123515 :         sql_column *priv_priv = find_sql_column(privs, "privileges");
     474      123515 :         sqlstore *store = m->session->tr->store;
     475             : 
     476      123515 :         return store->table_api.column_find_row(m->session->tr, priv_obj, &obj_id, priv_auth, &auth_id, priv_priv, &priv, NULL);
     477             : }
     478             : 
     479             : int
     480      123508 : sql_privilege(mvc *m, sqlid auth_id, sqlid obj_id, int priv)
     481             : {
     482      123508 :         oid rid = sql_privilege_rid(m, auth_id, obj_id, priv);
     483      123508 :         int res = -1;
     484             : 
     485      123508 :         if (!is_oid_nil(rid)) {
     486             :                 /* found priv */
     487        1070 :                 res = priv;
     488             :         }
     489      123508 :         return res;
     490             : }
     491             : 
     492             : int
     493         294 : global_privs(mvc *m, int priv)
     494             : {
     495         300 :         if (admin_privs(m->user_id) || admin_privs(m->role_id) ||
     496          10 :             sql_privilege(m, m->user_id, GLOBAL_OBJID, priv) == priv ||
     497           8 :             sql_privilege(m, m->role_id, GLOBAL_OBJID, priv) == priv ||
     498           4 :             sql_privilege(m, ROLE_PUBLIC, GLOBAL_OBJID, priv) == priv) {
     499         290 :                 return 1;
     500             :         }
     501             :         return 0;
     502             : }
     503             : 
     504             : int
     505      659723 : table_privs(mvc *m, sql_table *t, int priv)
     506             : {
     507             :         /* temporary tables are owned by the session user */
     508      659723 :         if (t->persistence == SQL_DECLARED_TABLE ||
     509      659563 :             (!t->system && t->persistence != SQL_PERSIST) ||
     510      490948 :             (priv == PRIV_SELECT && (t->persistence != SQL_PERSIST || t->commit_action)))
     511             :                 return 1;
     512      619865 :         if (admin_privs(m->user_id) || admin_privs(m->role_id) ||
     513        2470 :             (t->s && (m->user_id == t->s->auth_id || m->role_id == t->s->auth_id)) ||
     514        2020 :             sql_privilege(m, m->user_id, t->base.id, priv) == priv ||
     515        1922 :             sql_privilege(m, m->role_id, t->base.id, priv) == priv ||
     516         953 :             sql_privilege(m, ROLE_PUBLIC, t->base.id, priv) == priv) {
     517      619666 :                 return 1;
     518             :         }
     519             :         return 0;
     520             : }
     521             : 
     522             : int
     523         546 : column_privs(mvc *m, sql_column *c, int priv)
     524             : {
     525             :         /* only SELECT and UPDATE privileges for columns are available */
     526             :         /* temporary tables are owned by the session user, so does it's columns */
     527         546 :         if (c->t->persistence == SQL_DECLARED_TABLE ||
     528         546 :             (!c->t->system && c->t->persistence != SQL_PERSIST) ||
     529         546 :             (priv == PRIV_SELECT && (c->t->persistence != SQL_PERSIST || c->t->commit_action)))
     530             :                 return 1;
     531         546 :         if (admin_privs(m->user_id) || admin_privs(m->role_id) ||
     532        1092 :             (c->t->s && (m->user_id == c->t->s->auth_id || m->role_id == c->t->s->auth_id)) ||
     533        1026 :             sql_privilege(m, m->user_id, c->base.id, priv) == priv ||
     534         953 :             sql_privilege(m, m->role_id, c->base.id, priv) == priv ||
     535         473 :             sql_privilege(m, ROLE_PUBLIC, c->base.id, priv) == priv) {
     536          73 :                 return 1;
     537             :         }
     538             :         return 0;
     539             : }
     540             : 
     541             : int
     542      922084 : execute_priv(mvc *m, sql_func *f)
     543             : {
     544      922084 :         int priv = PRIV_EXECUTE;
     545             : 
     546      922376 :         if (!f->s || admin_privs(m->user_id) || admin_privs(m->role_id))
     547             :                 return 1;
     548         301 :         if (m->user_id == f->s->auth_id || m->role_id == f->s->auth_id)
     549             :                 return 1;
     550         255 :         if (sql_privilege(m, m->user_id, f->base.id, priv) == priv ||
     551         226 :             sql_privilege(m, m->role_id, f->base.id, priv) == priv ||
     552         113 :             sql_privilege(m, ROLE_PUBLIC, f->base.id, priv) == priv)
     553         133 :                 return 1;
     554             :         return 0;
     555             : }
     556             : 
     557             : static bool
     558           7 : role_granting_privs(mvc *m, oid role_rid, sqlid role_id, sqlid grantor_id)
     559             : {
     560           7 :         sql_schema *sys = find_sql_schema(m->session->tr, "sys");
     561           7 :         sql_table *auths = find_sql_table(m->session->tr, sys, "auths");
     562           7 :         sql_column *auths_grantor = find_sql_column(auths, "grantor");
     563           7 :         sqlid owner_id;
     564           7 :         sqlstore *store = m->session->tr->store;
     565             : 
     566           7 :         owner_id = store->table_api.column_find_sqlid(m->session->tr, auths_grantor, role_rid);
     567           7 :         if (owner_id == grantor_id)
     568             :                 return true;
     569           7 :         if (sql_privilege(m, grantor_id, role_id, PRIV_ROLE_ADMIN) == PRIV_ROLE_ADMIN)
     570             :                 return true;
     571             :         /* check for grant rights in the privs table */
     572             :         return false;
     573             : }
     574             : 
     575             : char *
     576          49 : sql_grant_role(mvc *m, str grantee, str role, sqlid grantor, int admin)
     577             : {
     578          49 :         oid rid;
     579          49 :         sql_schema *sys = find_sql_schema(m->session->tr, "sys");
     580          49 :         sql_table *auths = find_sql_table(m->session->tr, sys, "auths");
     581          49 :         sql_table *roles = find_sql_table(m->session->tr, sys, "user_role");
     582          49 :         sql_column *auths_name = find_sql_column(auths, "name");
     583          49 :         sql_column *auths_id = find_sql_column(auths, "id");
     584          49 :         sqlid role_id, grantee_id;
     585          49 :         sqlstore *store = m->session->tr->store;
     586          49 :         int log_res = LOG_OK;
     587             : 
     588          49 :         rid = store->table_api.column_find_row(m->session->tr, auths_name, role, NULL);
     589          49 :         if (is_oid_nil(rid))
     590           1 :                 throw(SQL, "sql.grant_role", SQLSTATE(M1M05) "GRANT: no such role '%s' or grantee '%s'", role, grantee);
     591          48 :         role_id = store->table_api.column_find_sqlid(m->session->tr, auths_id, rid);
     592          48 :         if (!is_oid_nil(backend_find_user(m, role)))
     593           0 :                 throw(SQL,"sql.grant_role", SQLSTATE(M1M05) "GRANT: '%s' is a USER not a ROLE", role);
     594          48 :         if (!admin_privs(grantor) && !role_granting_privs(m, rid, role_id, grantor))
     595           4 :                 throw(SQL,"sql.grant_role", SQLSTATE(0P000) "GRANT: Insufficient privileges to grant ROLE '%s'", role);
     596          44 :         rid = store->table_api.column_find_row(m->session->tr, auths_name, grantee, NULL);
     597          44 :         if (is_oid_nil(rid))
     598           1 :                 throw(SQL,"sql.grant_role", SQLSTATE(M1M05) "GRANT: no such role '%s' or grantee '%s'", role, grantee);
     599          43 :         grantee_id = store->table_api.column_find_sqlid(m->session->tr, auths_id, rid);
     600          43 :         rid = store->table_api.column_find_row(m->session->tr, find_sql_column(roles, "login_id"), &grantee_id, find_sql_column(roles, "role_id"), &role_id, NULL);
     601          43 :         if (!is_oid_nil(rid))
     602           2 :                 throw(SQL,"sql.grant_role", SQLSTATE(M1M05) "GRANT: User '%s' already has ROLE '%s'", grantee, role);
     603             : 
     604          41 :         if ((log_res = store->table_api.table_insert(m->session->tr, roles, &grantee_id, &role_id)) != LOG_OK)
     605           1 :                 throw(SQL, "sql.grant_role", SQLSTATE(42000) "GRANT: failed%s", log_res == LOG_CONFLICT ? " due to conflict with another transaction" : "");
     606          40 :         if (admin) {
     607           2 :                 int priv = PRIV_ROLE_ADMIN, one = 1;
     608           2 :                 sql_table *privs = find_sql_table(m->session->tr, sys, "privileges");
     609             : 
     610           2 :                 if ((log_res = store->table_api.table_insert(m->session->tr, privs, &role_id, &grantee_id, &priv, &grantor, &one)) != LOG_OK)
     611           0 :                         throw(SQL, "sql.grant_role", SQLSTATE(42000) "GRANT: failed%s", log_res == LOG_CONFLICT ? " due to conflict with another transaction" : "");
     612             :         }
     613             : 
     614             :         /* Add dependencies created */
     615          40 :         if ((log_res = sql_trans_add_dependency(m->session->tr, grantee_id, ddl)) != LOG_OK)
     616           0 :                 throw(SQL, "sql.grant_role", SQLSTATE(HY013) MAL_MALLOC_FAIL);
     617          40 :         if ((log_res = sql_trans_add_dependency(m->session->tr, role_id, ddl)) != LOG_OK)
     618           0 :                 throw(SQL, "sql.grant_role", SQLSTATE(HY013) MAL_MALLOC_FAIL);
     619          40 :         if ((log_res = sql_trans_add_dependency(m->session->tr, grantor, ddl)) != LOG_OK)
     620           0 :                 throw(SQL, "sql.grant_role", SQLSTATE(HY013) MAL_MALLOC_FAIL);
     621             :         return NULL;
     622             : }
     623             : 
     624             : char *
     625          10 : sql_revoke_role(mvc *m, str grantee, str role, sqlid grantor, int admin)
     626             : /* grantee no longer belongs the role (role) */
     627             : {
     628          10 :         oid rid;
     629          10 :         sql_schema *sys = find_sql_schema(m->session->tr, "sys");
     630          10 :         sql_table *auths = find_sql_table(m->session->tr, sys, "auths");
     631          10 :         sql_table *roles = find_sql_table(m->session->tr, sys, "user_role");
     632          10 :         sql_table *privs = find_sql_table(m->session->tr, sys, "privileges");
     633          10 :         sql_column *auths_name = find_sql_column(auths, "name");
     634          10 :         sql_column *auths_id = find_sql_column(auths, "id");
     635          10 :         sql_column *roles_role_id = find_sql_column(roles, "role_id");
     636          10 :         sql_column *roles_login_id = find_sql_column(roles, "login_id");
     637          10 :         sqlid role_id, grantee_id;
     638          10 :         sqlstore *store = m->session->tr->store;
     639          10 :         int log_res = LOG_OK;
     640             : 
     641          10 :         rid = store->table_api.column_find_row(m->session->tr, auths_name, grantee, NULL);
     642          10 :         if (is_oid_nil(rid))
     643           1 :                 throw(SQL,"sql.revoke_role", SQLSTATE(01006) "REVOKE: no such role '%s' or grantee '%s'", role, grantee);
     644           9 :         grantee_id = store->table_api.column_find_sqlid(m->session->tr, auths_id, rid);
     645           9 :         rid = store->table_api.column_find_row(m->session->tr, auths_name, role, NULL);
     646           9 :         if (is_oid_nil(rid))
     647           0 :                 throw(SQL,"sql.revoke_role", SQLSTATE(01006) "REVOKE: no such role '%s' or grantee '%s'", role, grantee);
     648           9 :         role_id = store->table_api.column_find_sqlid(m->session->tr, auths_id, rid);
     649           9 :         if (!admin_privs(grantor) && !role_granting_privs(m, rid, role_id, grantor))
     650           0 :                 throw(SQL,"sql.revoke_role", SQLSTATE(0P000) "REVOKE: insufficient privileges to revoke ROLE '%s'", role);
     651             : 
     652           9 :         if (!admin) {
     653           9 :                 rid = store->table_api.column_find_row(m->session->tr, roles_login_id, &grantee_id, roles_role_id, &role_id, NULL);
     654           9 :                 if (!is_oid_nil(rid)) {
     655           7 :                         if ((log_res = store->table_api.table_delete(m->session->tr, roles, rid)) != LOG_OK)
     656           0 :                                 throw(SQL, "sql.revoke_role", SQLSTATE(42000) "REVOKE: failed%s", log_res == LOG_CONFLICT ? " due to conflict with another transaction" : "");
     657             :                 } else
     658           2 :                         throw(SQL,"sql.revoke_role", SQLSTATE(01006) "REVOKE: User '%s' does not have ROLE '%s'", grantee, role);
     659             :         }
     660           7 :         rid = sql_privilege_rid(m, grantee_id, role_id, PRIV_ROLE_ADMIN);
     661           7 :         if (!is_oid_nil(rid)) {
     662           1 :                 if ((log_res = store->table_api.table_delete(m->session->tr, privs, rid)) != LOG_OK)
     663           0 :                         throw(SQL, "sql.revoke_role", SQLSTATE(42000) "REVOKE: failed%s", log_res == LOG_CONFLICT ? " due to conflict with another transaction" : "");
     664           6 :         } else if (admin)
     665           0 :                 throw(SQL,"sql.revoke_role", SQLSTATE(01006) "REVOKE: User '%s' does not have ROLE '%s'", grantee, role);
     666             :         return NULL;
     667             : }
     668             : 
     669             : sqlid
     670      118838 : sql_find_auth(mvc *m, str auth)
     671             : {
     672      118838 :         sqlid res = -1;
     673      118838 :         oid rid;
     674      118838 :         sql_schema *sys = find_sql_schema(m->session->tr, "sys");
     675      118838 :         sql_table *auths = find_sql_table(m->session->tr, sys, "auths");
     676      118838 :         sql_column *auths_name = find_sql_column(auths, "name");
     677      118838 :         sqlstore *store = m->session->tr->store;
     678             : 
     679      118838 :         rid = store->table_api.column_find_row(m->session->tr, auths_name, auth, NULL);
     680             : 
     681      118838 :         if (!is_oid_nil(rid)) {
     682      118828 :                 sql_column *auths_id = find_sql_column(auths, "id");
     683      118828 :                 sqlid p = store->table_api.column_find_sqlid(m->session->tr, auths_id, rid);
     684             : 
     685      118828 :                 if (p > -1)
     686      118838 :                         res = p;
     687             :         }
     688      118838 :         return res;
     689             : }
     690             : 
     691             : int
     692         170 : sql_schema_has_user(mvc *m, sql_schema *s)
     693             : {
     694         170 :         return(backend_schema_has_user(m, s));
     695             : }
     696             : 
     697             : static int
     698           6 : sql_grantable_(mvc *m, sqlid grantorid, sqlid obj_id, int privs)
     699             : {
     700           6 :         oid rid;
     701           6 :         sql_schema *sys = find_sql_schema(m->session->tr, "sys");
     702           6 :         sql_table *prvs = find_sql_table(m->session->tr, sys, "privileges");
     703           6 :         sql_column *priv_obj = find_sql_column(prvs, "obj_id");
     704           6 :         sql_column *priv_auth = find_sql_column(prvs, "auth_id");
     705           6 :         sql_column *priv_priv = find_sql_column(prvs, "privileges");
     706           6 :         sql_column *priv_allowed = find_sql_column(prvs, "grantable");
     707           6 :         sqlstore *store = m->session->tr->store;
     708           6 :         int priv;
     709             : 
     710          24 :         for (priv = 1; priv <= privs; priv <<= 1) {
     711          18 :                 if (!(priv & privs))
     712           8 :                         continue;
     713          10 :                 rid = store->table_api.column_find_row(m->session->tr, priv_obj, &obj_id, priv_auth, &grantorid, priv_priv, &priv, NULL);
     714          10 :                 if (!is_oid_nil(rid)) {
     715           4 :                         int allowed = store->table_api.column_find_int(m->session->tr, priv_allowed, rid);
     716             : 
     717             :                         /* switch of priv bit */
     718           4 :                         if (allowed)
     719           4 :                                 privs = (privs & ~priv);
     720             :                 }
     721             :         }
     722           6 :         if (privs != 0)
     723           2 :                 return 0;
     724             :         return 1;
     725             : }
     726             : 
     727             : int
     728           7 : sql_grantable(mvc *m, sqlid grantorid, sqlid obj_id, int privs)
     729             : {
     730           7 :         if (admin_privs(m->user_id) || admin_privs(m->role_id))
     731             :                 return 1;
     732           6 :         return sql_grantable_(m, grantorid, obj_id, privs);
     733             : }
     734             : 
     735             : sqlid
     736          34 : mvc_set_role(mvc *m, char *role)
     737             : {
     738          34 :         oid rid;
     739          34 :         sql_schema *sys = find_sql_schema(m->session->tr, "sys");
     740          34 :         sql_table *auths = find_sql_table(m->session->tr, sys, "auths");
     741          34 :         sql_column *auths_name = find_sql_column(auths, "name");
     742          34 :         sqlid res = 0;
     743          34 :         sqlstore *store = m->session->tr->store;
     744             : 
     745          34 :         TRC_DEBUG(SQL_TRANS, "Set role: %s\n", role);
     746             : 
     747          34 :         rid = store->table_api.column_find_row(m->session->tr, auths_name, role, NULL);
     748          34 :         if (!is_oid_nil(rid)) {
     749          32 :                 sql_column *auths_id = find_sql_column(auths, "id");
     750          32 :                 sqlid id = store->table_api.column_find_sqlid(m->session->tr, auths_id, rid);
     751             : 
     752          32 :                 if (m->user_id == id) {
     753           3 :                         m->role_id = id;
     754           3 :                         res = 1;
     755             :                 } else {
     756          29 :                         sql_table *roles = find_sql_table(m->session->tr, sys, "user_role");
     757          29 :                         sql_column *role_id = find_sql_column(roles, "role_id");
     758          29 :                         sql_column *login_id = find_sql_column(roles, "login_id");
     759             : 
     760          29 :                         rid = store->table_api.column_find_row(m->session->tr, login_id, &m->user_id, role_id, &id, NULL);
     761          29 :                         if (!is_oid_nil(rid)) {
     762          22 :                                 m->role_id = id;
     763          22 :                                 res = 1;
     764             :                         }
     765             :                 }
     766             :         }
     767          34 :         return res;
     768             : }
     769             : 
     770             : int
     771       37320 : mvc_set_schema(mvc *m, char *schema)
     772             : {
     773       37320 :         int ret = 0;
     774       37320 :         sql_schema *s = find_sql_schema(m->session->tr, schema);
     775       37321 :         char* new_schema_name = sa_strdup(m->session->sa, schema);
     776             : 
     777       37322 :         if (s && new_schema_name) {
     778       37321 :                 m->session->schema_name = new_schema_name;
     779       37321 :                 m->type = Q_SCHEMA;
     780       37321 :                 if (m->session->tr->active)
     781       37321 :                         m->session->schema = s;
     782             :                 ret = 1;
     783             :         }
     784       37322 :         return ret;
     785             : }
     786             : 
     787             : char *
     788         359 : sql_create_user(mvc *sql, char *user, char *passwd, bool enc, char *fullname, char *schema, char *schema_path, lng max_memory, int max_workers, char *optimizer, char *role)
     789             : {
     790         359 :         char *err;
     791         359 :         sql_schema *s = NULL;
     792         359 :         sqlid schema_id = 0;
     793         359 :         sqlid role_id = 0;
     794             : 
     795         359 :         if (role)
     796           9 :                 if (backend_find_role(sql, role, &role_id) < 0)
     797           0 :                         throw(SQL,"sql.create_user", SQLSTATE(42M31) "CREATE USER: no such role '%s'", role);
     798             : 
     799         359 :         if (!admin_privs(sql->user_id) && !admin_privs(sql->role_id))
     800           1 :                 throw(SQL,"sql.create_user", SQLSTATE(42M31) "Insufficient privileges to create user '%s'", user);
     801             : 
     802         358 :         if (!is_oid_nil(backend_find_user(sql, user)))
     803           1 :                 throw(SQL,"sql.create_user", SQLSTATE(42M31) "CREATE USER: user '%s' already exists", user);
     804             : 
     805         357 :         if (schema) {
     806         324 :                 if (!(s = find_sql_schema(sql->session->tr, schema)))
     807           1 :                         throw(SQL,"sql.create_user", SQLSTATE(3F000) "CREATE USER: no such schema '%s'", schema);
     808         323 :                 schema_id = s->base.id;
     809         323 :                 if (!isNew(s) && sql_trans_add_dependency(sql->session->tr, schema_id, ddl) != LOG_OK)
     810           0 :                         throw(SQL, "sql.create_user", SQLSTATE(HY013) MAL_MALLOC_FAIL);
     811             : 
     812             :         } else {
     813             :                 // look for an existing schema matching user
     814          33 :                 if ((s = find_sql_schema(sql->session->tr, user))) {
     815           0 :                         schema_id = s->base.id;
     816           0 :                         if (!isNew(s) && sql_trans_add_dependency(sql->session->tr, schema_id, ddl) != LOG_OK)
     817           0 :                                 throw(SQL, "sql.create_user", SQLSTATE(HY013) MAL_MALLOC_FAIL);
     818             :                 }
     819             :         }
     820             : 
     821             : 
     822         356 :         if (sql_trans_add_dependency(sql->session->tr, sql->user_id, ddl) != LOG_OK)
     823           0 :                 throw(SQL, "sql.create_user", SQLSTATE(HY013) MAL_MALLOC_FAIL);
     824             : 
     825         356 :         if ((err = backend_create_user(sql, user, passwd, enc, fullname, schema_id, schema_path, sql->user_id, max_memory,
     826             :                                         max_workers, optimizer, role_id)) != NULL)
     827             :         {
     828             :                 /* strip off MAL exception decorations */
     829           2 :                 char *r;
     830           2 :                 char *e = err;
     831           2 :                 if ((e = strchr(e, ':')) == NULL) {
     832             :                         e = err;
     833           2 :                 } else if ((e = strchr(++e, ':')) == NULL) {
     834             :                         e = err;
     835             :                 } else {
     836           2 :                         e++;
     837             :                 }
     838           2 :                 r = createException(SQL,"sql.create_user", SQLSTATE(M0M27) "CREATE USER: %s", e);
     839           2 :                 _DELETE(err);
     840           2 :                 return r;
     841             :         }
     842             : 
     843             :         /* the default role must explicitly granted to the new user */
     844         354 :         if (role_id) {
     845           9 :                 str r;
     846             :                 /* - we don't grant the default role WITH ADMIN OPTION hence admin=0
     847             :                  * - we should use sql->role_id instead of sql->user_id otherwise a user with high privs
     848             :                  * (e.g. sysadmin) might not be able to GRANT the DEFAULT ROLE (see sql_grant_role() impl)
     849             :                  */
     850           9 :                 if ((r = sql_grant_role(sql, user, role, sql->role_id, 0)))
     851             :                         return r;
     852             :         }
     853             : 
     854             :         return NULL;
     855             : }
     856             : 
     857             : static int
     858           0 : id_cmp(sqlid *id1, sqlid *id2)
     859             : {
     860           0 :         return *id1 == *id2;
     861             : }
     862             : 
     863             : static char *
     864         107 : sql_drop_granted_users(mvc *sql, sqlid user_id, char *user, list *deleted_users)
     865             : {
     866         107 :         sql_schema *ss = mvc_bind_schema(sql, "sys");
     867         107 :         sql_table *privs = find_sql_table(sql->session->tr, ss, "privileges");
     868         107 :         sql_table *user_roles = find_sql_table(sql->session->tr, ss, "user_role");
     869         107 :         sql_table *auths = find_sql_table(sql->session->tr, ss, "auths");
     870         107 :         sql_trans *tr = sql->session->tr;
     871         107 :         sqlstore *store = tr->store;
     872         107 :         rids *A;
     873         107 :         oid rid;
     874         107 :         int log_res = LOG_OK;
     875         107 :         char *msg = NULL;
     876             : 
     877         107 :         if (!list_find(deleted_users, &user_id, (fcmp) &id_cmp)) {
     878         107 :                 if (mvc_check_dependency(sql, user_id, OWNER_DEPENDENCY, NULL))
     879          11 :                         throw(SQL,"sql.drop_user",SQLSTATE(M1M05) "DROP USER: '%s' owns a schema", user);
     880          96 :                 if (backend_drop_user(sql, user) == FALSE)
     881           0 :                         throw(SQL,"sql.drop_user",SQLSTATE(M0M27) "%s", sql->errstr);
     882             : 
     883             :                 /* select privileges of this user_id */
     884          96 :                 A = store->table_api.rids_select(tr, find_sql_column(privs, "auth_id"), &user_id, &user_id, NULL);
     885          96 :                 if (!A)
     886           0 :                         throw(SQL, "sql.drop_user", SQLSTATE(HY013) MAL_MALLOC_FAIL);
     887             :                 /* remove them */
     888         131 :                 for(rid = store->table_api.rids_next(A); !is_oid_nil(rid) && log_res == LOG_OK; rid = store->table_api.rids_next(A))
     889          35 :                         log_res = store->table_api.table_delete(tr, privs, rid);
     890          96 :                 store->table_api.rids_destroy(A);
     891          96 :                 if (log_res != LOG_OK)
     892           0 :                         throw(SQL, "sql.drop_user", SQLSTATE(42000) "DROP USER: failed%s", log_res == LOG_CONFLICT ? " due to conflict with another transaction" : "");
     893             : 
     894             :                 /* select privileges granted by this user_id */
     895          96 :                 A = store->table_api.rids_select(tr, find_sql_column(privs, "grantor"), &user_id, &user_id, NULL);
     896          96 :                 if (!A)
     897           0 :                         throw(SQL, "sql.drop_user", SQLSTATE(HY013) MAL_MALLOC_FAIL);
     898             :                 /* remove them */
     899          96 :                 for(rid = store->table_api.rids_next(A); !is_oid_nil(rid) && log_res == LOG_OK; rid = store->table_api.rids_next(A))
     900           0 :                         log_res = store->table_api.table_delete(tr, privs, rid);
     901          96 :                 store->table_api.rids_destroy(A);
     902          96 :                 if (log_res != LOG_OK)
     903           0 :                         throw(SQL, "sql.drop_user", SQLSTATE(42000) "DROP USER: failed%s", log_res == LOG_CONFLICT ? " due to conflict with another transaction" : "");
     904             : 
     905             :                 /* delete entry from auths table */
     906          96 :                 rid = store->table_api.column_find_row(tr, find_sql_column(auths, "name"), user, NULL);
     907          96 :                 if (is_oid_nil(rid))
     908           6 :                         throw(SQL, "sql.drop_user", SQLSTATE(0P000) "DROP USER: no such user role '%s'", user);
     909          90 :                 if ((log_res = store->table_api.table_delete(tr, auths, rid)) != LOG_OK)
     910           0 :                         throw(SQL, "sql.drop_user", SQLSTATE(42000) "DROP USER: failed%s", log_res == LOG_CONFLICT ? " due to conflict with another transaction" : "");
     911             : 
     912             :                 /* select user roles of this user_id */
     913          90 :                 A = store->table_api.rids_select(tr, find_sql_column(user_roles, "login_id"), &user_id, &user_id, NULL);
     914          90 :                 if (!A)
     915           0 :                         throw(SQL, "sql.drop_user", SQLSTATE(HY013) MAL_MALLOC_FAIL);
     916             :                 /* remove them */
     917         115 :                 for(rid = store->table_api.rids_next(A); !is_oid_nil(rid) && log_res == LOG_OK; rid = store->table_api.rids_next(A))
     918          25 :                         log_res = store->table_api.table_delete(tr, user_roles, rid);
     919          90 :                 store->table_api.rids_destroy(A);
     920          90 :                 if (log_res != LOG_OK)
     921           0 :                         throw(SQL, "sql.drop_user", SQLSTATE(42000) "DROP USER: failed%s", log_res == LOG_CONFLICT ? " due to conflict with another transaction" : "");
     922             : 
     923          90 :                 list_append(deleted_users, &user_id);
     924             : 
     925             :                 /* select users created by this user_id */
     926          90 :                 A = store->table_api.rids_select(tr, find_sql_column(auths, "grantor"), &user_id, &user_id, NULL);
     927          90 :                 if (!A)
     928           0 :                         throw(SQL, "sql.drop_user", SQLSTATE(HY013) MAL_MALLOC_FAIL);
     929             :                 /* remove them and continue the deletion */
     930          90 :                 for(rid = store->table_api.rids_next(A); !is_oid_nil(rid) && log_res == LOG_OK && msg; rid = store->table_api.rids_next(A)) {
     931             :                         sqlid nuid = store->table_api.column_find_sqlid(tr, find_sql_column(auths, "id"), rid);
     932             :                         char *nname = store->table_api.column_find_value(tr, find_sql_column(auths, "name"), rid);
     933             : 
     934             :                         if (!nname)
     935             :                                 msg = createException(SQL, "sql.drop_user", SQLSTATE(HY013) MAL_MALLOC_FAIL);
     936             :                         else if (!(msg = sql_drop_granted_users(sql, nuid, nname, deleted_users)))
     937             :                                 log_res = store->table_api.table_delete(tr, auths, rid);
     938             :                         _DELETE(nname);
     939             :                 }
     940          90 :                 store->table_api.rids_destroy(A);
     941          90 :                 if (!msg && log_res != LOG_OK)
     942             :                         throw(SQL, "sql.drop_user", SQLSTATE(42000) "DROP USER: failed%s", log_res == LOG_CONFLICT ? " due to conflict with another transaction" : "");
     943             :         }
     944             :         return msg;
     945             : }
     946             : 
     947             : char *
     948         107 : sql_drop_user(mvc *sql, char *user)
     949             : {
     950         107 :         sqlid user_id = sql_find_auth(sql, user);
     951         107 :         list *deleted = list_create(NULL);
     952         107 :         str msg = NULL;
     953             : 
     954         107 :         if (!deleted)
     955           0 :                 throw(SQL, "sql.drop_user", SQLSTATE(HY013) MAL_MALLOC_FAIL);
     956         107 :         msg = sql_drop_granted_users(sql, user_id, user, deleted);
     957         107 :         list_destroy(deleted);
     958             : 
     959             :         /* Flag as removed */
     960         107 :         if (!msg && sql_trans_add_dependency_change(sql->session->tr, user_id, ddl) != LOG_OK)
     961           0 :                 throw(SQL, "sql.drop_user", SQLSTATE(HY013) MAL_MALLOC_FAIL);
     962             :         return msg;
     963             : }
     964             : 
     965             : char *
     966          83 : sql_alter_user(mvc *sql, char *user, char *passwd, bool enc, char *schema, char *schema_path, char *oldpasswd, char *role, lng max_memory, int max_workers)
     967             : {
     968          83 :         sql_schema *s = NULL;
     969          83 :         sqlid schema_id = 0;
     970          83 :         sqlid role_id = 0;
     971             : 
     972          83 :         if (role)
     973           3 :                 if (backend_find_role(sql, role, &role_id) < 0)
     974           0 :                         throw(SQL,"sql.create_user", SQLSTATE(42M31) "ALTER USER: no such role '%s'", role);
     975             : 
     976             :         /* we may be called from MAL (nil) */
     977         164 :         if (strNil(user))
     978             :                 user = NULL;
     979             :         /* USER == NULL -> current_user */
     980             : 
     981          83 :         if (!admin_privs(sql->user_id) && !admin_privs(sql->role_id) && user != NULL && strcmp(user, get_string_global_var(sql, "current_user")) != 0)
     982           0 :                 throw(SQL,"sql.alter_user", SQLSTATE(M1M05) "Insufficient privileges to change user '%s'", user);
     983             : 
     984          81 :         if (user != NULL && is_oid_nil(backend_find_user(sql, user)))
     985           1 :                 throw(SQL,"sql.alter_user", SQLSTATE(42M32) "ALTER USER: no such user '%s'", user);
     986          82 :         if (schema) {
     987          64 :                 if (!(s = find_sql_schema(sql->session->tr, schema)))
     988           1 :                         throw(SQL,"sql.alter_user", SQLSTATE(3F000) "ALTER USER: no such schema '%s'", schema);
     989          63 :                 schema_id = s->base.id;
     990          63 :                 if (!isNew(s) && sql_trans_add_dependency(sql->session->tr, s->base.id, ddl) != LOG_OK)
     991           0 :                         throw(SQL, "sql.alter_user", SQLSTATE(HY013) MAL_MALLOC_FAIL);
     992             :         }
     993          81 :         if (backend_alter_user(sql, user, passwd, enc, schema_id, schema_path, oldpasswd, role_id, max_memory, max_workers) == FALSE)
     994           5 :                 throw(SQL,"sql.alter_user", SQLSTATE(M0M27) "%s", sql->errstr);
     995             :         return NULL;
     996             : }
     997             : 
     998             : char *
     999           5 : sql_rename_user(mvc *sql, char *olduser, char *newuser)
    1000             : {
    1001           5 :         if (!admin_privs(sql->user_id) && !admin_privs(sql->role_id))
    1002           1 :                 throw(SQL,"sql.rename_user", SQLSTATE(M1M05) "ALTER USER: insufficient privileges to rename user '%s'", olduser);
    1003             : 
    1004           4 :         if (is_oid_nil(backend_find_user(sql, olduser)))
    1005           1 :                 throw(SQL,"sql.rename_user", SQLSTATE(42M32) "ALTER USER: no such user '%s'", olduser);
    1006           3 :         if (!is_oid_nil(backend_find_user(sql, newuser)))
    1007           1 :                 throw(SQL,"sql.rename_user", SQLSTATE(42M31) "ALTER USER: user '%s' already exists", newuser);
    1008           2 :         if (backend_rename_user(sql, olduser, newuser) == FALSE)
    1009           0 :                 throw(SQL,"sql.rename_user", SQLSTATE(M1M05) "%s", sql->errstr);
    1010             :         return NULL;
    1011             : }
    1012             : 
    1013             : int
    1014         226 : sql_create_privileges(mvc *m, sql_schema *s, const char *initpasswd)
    1015             : {
    1016         226 :         int pub, su, p, zero = 0;
    1017         226 :         sql_table *t = NULL, *privs = NULL;
    1018         226 :         sql_column *col = NULL;
    1019         226 :         sql_subfunc *f = NULL;
    1020         226 :         sql_trans *tr = m->session->tr;
    1021             : 
    1022             :         // create db_user_info tbl
    1023         226 :         backend_create_privileges(m, s, initpasswd);
    1024             : 
    1025         226 :         mvc_create_table(&t, m, s, "user_role", tt_table, 1, SQL_PERSIST, 0, -1, 0);
    1026         226 :         mvc_create_column_(&col, m, t, "login_id", "int", 32);
    1027         226 :         mvc_create_column_(&col, m, t, "role_id", "int", 32);
    1028             : 
    1029             :         /* all roles and users are in the auths table */
    1030         226 :         mvc_create_table(&t, m, s, "auths", tt_table, 1, SQL_PERSIST, 0, -1, 0);
    1031         226 :         mvc_create_column_(&col, m, t, "id", "int", 32);
    1032         226 :         mvc_create_column_(&col, m, t, "name", "varchar", 1024);
    1033         226 :         mvc_create_column_(&col, m, t, "grantor", "int", 32);
    1034             : 
    1035         226 :         mvc_create_table(&t, m, s, "privileges", tt_table, 1, SQL_PERSIST, 0, -1, 0);
    1036         226 :         mvc_create_column_(&col, m, t, "obj_id", "int", 32);
    1037         226 :         mvc_create_column_(&col, m, t, "auth_id", "int", 32);
    1038         226 :         mvc_create_column_(&col, m, t, "privileges", "int", 32);
    1039         226 :         mvc_create_column_(&col, m, t, "grantor", "int", 32);
    1040         226 :         mvc_create_column_(&col, m, t, "grantable", "int", 32);
    1041             : 
    1042             :         /* add roles public and sysadmin and user monetdb */
    1043         226 :         sql_create_auth_id(m, ROLE_PUBLIC, "public");
    1044         226 :         sql_create_auth_id(m, ROLE_SYSADMIN, "sysadmin");
    1045         226 :         sql_create_auth_id(m, USER_MONETDB, "monetdb");
    1046             : 
    1047         226 :         pub = ROLE_PUBLIC;
    1048         226 :         su = USER_MONETDB;
    1049         226 :         p = PRIV_SELECT;
    1050         226 :         privs = find_sql_table(tr, s, "privileges");
    1051             : 
    1052         226 :         sqlstore *store = m->session->tr->store;
    1053         226 :         t = find_sql_table(tr, s, "schemas");
    1054         226 :         store->table_api.table_insert(m->session->tr, privs, &t->base.id, &pub, &p, &zero, &zero);
    1055         226 :         t = find_sql_table(tr, s, "types");
    1056         226 :         store->table_api.table_insert(m->session->tr, privs, &t->base.id, &pub, &p, &zero, &zero);
    1057         226 :         t = find_sql_table(tr, s, "functions");
    1058         226 :         store->table_api.table_insert(m->session->tr, privs, &t->base.id, &pub, &p, &zero, &zero);
    1059         226 :         t = find_sql_table(tr, s, "args");
    1060         226 :         store->table_api.table_insert(m->session->tr, privs, &t->base.id, &pub, &p, &zero, &zero);
    1061         226 :         t = find_sql_table(tr, s, "sequences");
    1062         226 :         store->table_api.table_insert(m->session->tr, privs, &t->base.id, &pub, &p, &zero, &zero);
    1063         226 :         t = find_sql_table(tr, s, "dependencies");
    1064         226 :         store->table_api.table_insert(m->session->tr, privs, &t->base.id, &pub, &p, &zero, &zero);
    1065         226 :         t = find_sql_table(tr, s, "_tables");
    1066         226 :         store->table_api.table_insert(m->session->tr, privs, &t->base.id, &pub, &p, &zero, &zero);
    1067         226 :         t = find_sql_table(tr, s, "_columns");
    1068         226 :         store->table_api.table_insert(m->session->tr, privs, &t->base.id, &pub, &p, &zero, &zero);
    1069         226 :         t = find_sql_table(tr, s, "keys");
    1070         226 :         store->table_api.table_insert(m->session->tr, privs, &t->base.id, &pub, &p, &zero, &zero);
    1071         226 :         t = find_sql_table(tr, s, "idxs");
    1072         226 :         store->table_api.table_insert(m->session->tr, privs, &t->base.id, &pub, &p, &zero, &zero);
    1073         226 :         t = find_sql_table(tr, s, "triggers");
    1074         226 :         store->table_api.table_insert(m->session->tr, privs, &t->base.id, &pub, &p, &zero, &zero);
    1075         226 :         t = find_sql_table(tr, s, "objects");
    1076         226 :         store->table_api.table_insert(m->session->tr, privs, &t->base.id, &pub, &p, &zero, &zero);
    1077         226 :         t = find_sql_table(tr, s, "tables");
    1078         226 :         store->table_api.table_insert(m->session->tr, privs, &t->base.id, &pub, &p, &zero, &zero);
    1079         226 :         t = find_sql_table(tr, s, "columns");
    1080         226 :         store->table_api.table_insert(m->session->tr, privs, &t->base.id, &pub, &p, &zero, &zero);
    1081         226 :         t = find_sql_table(tr, s, "comments");
    1082         226 :         store->table_api.table_insert(m->session->tr, privs, &t->base.id, &pub, &p, &zero, &zero);
    1083         226 :         t = find_sql_table(tr, s, "user_role");
    1084         226 :         store->table_api.table_insert(m->session->tr, privs, &t->base.id, &pub, &p, &zero, &zero);
    1085         226 :         t = find_sql_table(tr, s, "auths");
    1086         226 :         store->table_api.table_insert(m->session->tr, privs, &t->base.id, &pub, &p, &zero, &zero);
    1087         226 :         t = find_sql_table(tr, s, "privileges");
    1088         226 :         store->table_api.table_insert(m->session->tr, privs, &t->base.id, &pub, &p, &zero, &zero);
    1089         226 :         t = find_sql_table(tr, s, "table_partitions");
    1090         226 :         store->table_api.table_insert(m->session->tr, privs, &t->base.id, &pub, &p, &zero, &zero);
    1091         226 :         t = find_sql_table(tr, s, "range_partitions");
    1092         226 :         store->table_api.table_insert(m->session->tr, privs, &t->base.id, &pub, &p, &zero, &zero);
    1093         226 :         t = find_sql_table(tr, s, "value_partitions");
    1094         226 :         store->table_api.table_insert(m->session->tr, privs, &t->base.id, &pub, &p, &zero, &zero);
    1095             :         // restrict access to db_user_info to monetdb role
    1096         226 :         t = find_sql_table(tr, s, "db_user_info");
    1097         226 :         store->table_api.table_insert(m->session->tr, privs, &t->base.id, &su, &p, &zero, &zero);
    1098             : 
    1099             : 
    1100         226 :         p = PRIV_EXECUTE;
    1101         226 :         f = sql_bind_func_(m, s->base.name, "env", NULL, F_UNION, true, true);
    1102         226 :         store->table_api.table_insert(m->session->tr, privs, &f->func->base.id, &pub, &p, &zero, &zero);
    1103         226 :         f = sql_bind_func_(m, s->base.name, "var", NULL, F_UNION, true, true);
    1104         226 :         store->table_api.table_insert(m->session->tr, privs, &f->func->base.id, &pub, &p, &zero, &zero);
    1105             : 
    1106             :         /* owned by the users anyway
    1107             :         s = mvc_bind_schema(m, "tmp");
    1108             :         t = find_sql_table(tr, s, "profile");
    1109             :         store->table_api.table_insert(m->session->tr, privs, &t->base.id, &pub, &p, &zero, &zero);
    1110             :         t = find_sql_table(tr, s, "_tables");
    1111             :         store->table_api.table_insert(m->session->tr, privs, &t->base.id, &pub, &p, &zero, &zero);
    1112             :         t = find_sql_table(tr, s, "_columns");
    1113             :         store->table_api.table_insert(m->session->tr, privs, &t->base.id, &pub, &p, &zero, &zero);
    1114             :         t = find_sql_table(tr, s, "keys");
    1115             :         store->table_api.table_insert(m->session->tr, privs, &t->base.id, &pub, &p, &zero, &zero);
    1116             :         t = find_sql_table(tr, s, "idxs");
    1117             :         store->table_api.table_insert(m->session->tr, privs, &t->base.id, &pub, &p, &zero, &zero);
    1118             :         t = find_sql_table(tr, s, "triggers");
    1119             :         store->table_api.table_insert(m->session->tr, privs, &t->base.id, &pub, &p, &zero, &zero);
    1120             :         t = find_sql_table(tr, s, "objects");
    1121             :         store->table_api.table_insert(m->session->tr, privs, &t->base.id, &pub, &p, &zero, &zero);
    1122             :         */
    1123             : 
    1124         226 :         return 0;
    1125             : }

Generated by: LCOV version 1.14