LCOV - code coverage report
Current view: top level - sql/backends/monet5 - sql_user.c (source / functions) Hit Total Coverage
Test: coverage.info Lines: 259 397 65.2 %
Date: 2021-10-13 02:24:04 Functions: 12 14 85.7 %

          Line data    Source code
       1             : /*
       2             :  * This Source Code Form is subject to the terms of the Mozilla Public
       3             :  * License, v. 2.0.  If a copy of the MPL was not distributed with this
       4             :  * file, You can obtain one at http://mozilla.org/MPL/2.0/.
       5             :  *
       6             :  * Copyright 1997 - July 2008 CWI, August 2008 - 2021 MonetDB B.V.
       7             :  */
       8             : 
       9             : /*
      10             :  * @f sql_user
      11             :  * @t SQL catalog management
      12             :  * @a N. Nes, F. Groffen
      13             :  * @+ SQL user
      14             :  * The SQL user and authorisation implementation differs per backend.  This
      15             :  * file implements the authorisation and user management based on the M5
      16             :  * system authorisation.
      17             :  */
      18             : #include "monetdb_config.h"
      19             : #include "sql_user.h"
      20             : #include "sql_mvc.h"
      21             : #include "sql_privileges.h"
      22             : #include "mal_interpreter.h"
      23             : #include "mal_authorize.h"
      24             : #include "mcrypt.h"
      25             : 
      26             : static int
      27          75 : monet5_drop_user(ptr _mvc, str user)
      28             : {
      29             :         mvc *m = (mvc *) _mvc;
      30             :         oid rid, grant_user;
      31          75 :         sql_schema *sys = find_sql_schema(m->session->tr, "sys");
      32          75 :         sql_table *users = find_sql_table(m->session->tr, sys, "db_user_info");
      33          75 :         sql_column *users_name = find_sql_column(users, "name");
      34             :         str err;
      35          75 :         Client c = MCgetClient(m->clientid);
      36          75 :         sqlstore *store = m->session->tr->store;
      37             :         int log_res = LOG_OK;
      38             : 
      39          75 :         rid = store->table_api.column_find_row(m->session->tr, users_name, user, NULL);
      40          75 :         if (!is_oid_nil(rid) && (log_res = store->table_api.table_delete(m->session->tr, users, rid)) != LOG_OK) {
      41           0 :                 (void) sql_error(m, 02, "DROP USER: failed%s", log_res == LOG_CONFLICT ? " due to conflict with another transaction" : "");
      42           0 :                 return FALSE;
      43             :         }
      44             : 
      45          75 :         grant_user = c->user;
      46          75 :         c->user = MAL_ADMIN;
      47          75 :         err = AUTHremoveUser(c, user);
      48          75 :         c->user = grant_user;
      49          75 :         if (err !=MAL_SUCCEED) {
      50           1 :                 (void) sql_error(m, 02, "DROP USER: %s", getExceptionMessage(err));
      51           1 :                 freeException(err);
      52           1 :                 return FALSE;
      53             :         }
      54             :         /* FIXME: We have to ignore this inconsistency here, because the
      55             :          * user was already removed from the system authorisation. Once
      56             :          * we have warnings, we could issue a warning about this
      57             :          * (seemingly) inconsistency between system and sql shadow
      58             :          * administration. */
      59             : 
      60             :         return TRUE;
      61             : }
      62             : 
      63             : #define outside_str 1
      64             : #define inside_str 2
      65             : #define default_schema_path "\"sys\"" /* "sys" will be the default schema path */
      66             : 
      67             : static str
      68        5326 : parse_schema_path_str(mvc *m, str schema_path, bool build) /* this function for both building and validating the schema path */
      69             : {
      70        5326 :         list *l = m->schema_path;
      71             :         char next_schema[1024]; /* needs one extra character for null terminator */
      72             :         int status = outside_str;
      73             :         size_t bp = 0;
      74             : 
      75        5326 :         if (strNil(schema_path))
      76           0 :                 throw(SQL, "sql.schema_path", SQLSTATE(42000) "A schema path cannot be NULL");
      77             : 
      78        5326 :         if (build) {
      79       10102 :                 while (l->t) /* if building, empty schema_path list */
      80        5051 :                         (void) list_remove_node(l, NULL, l->t);
      81        5051 :                 m->schema_path_has_sys = 0;
      82        5051 :                 m->schema_path_has_tmp = 0;
      83             :         }
      84             : 
      85       34039 :         for (size_t i = 0; schema_path[i]; i++) {
      86             :                 char next = schema_path[i];
      87             : 
      88       28716 :                 if (next == '"') {
      89       10660 :                         if (status == inside_str && schema_path[i + 1] == '"') {
      90           2 :                                 next_schema[bp++] = '"';
      91           2 :                                 i++; /* has to advance two positions */
      92       10658 :                         } else if (status == inside_str) {
      93        5333 :                                 if (bp == 0)
      94           1 :                                         throw(SQL, "sql.schema_path", SQLSTATE(42000) "A schema name cannot be empty");
      95        5332 :                                 if (bp == 1023)
      96           1 :                                         throw(SQL, "sql.schema_path", SQLSTATE(42000) "A schema has up to 1023 characters");
      97             : 
      98        5331 :                                 if (build) {
      99             :                                         char *val = NULL;
     100        5056 :                                         next_schema[bp++] = '\0';
     101        5056 :                                         if (!(val = _STRDUP(next_schema)) || !list_append(l, val)) {
     102           0 :                                                 _DELETE(val);
     103           0 :                                                 throw(SQL, "sql.schema_path", SQLSTATE(HY013) MAL_MALLOC_FAIL);
     104             :                                         }
     105        5056 :                                         if (strcmp(next_schema, "sys") == 0)
     106        5047 :                                                 m->schema_path_has_sys = 1;
     107           9 :                                         else if (strcmp(next_schema, "tmp") == 0)
     108           0 :                                                 m->schema_path_has_tmp = 1;
     109             :                                 }
     110             : 
     111             :                                 bp = 0;
     112             :                                 status = outside_str;
     113             :                         } else {
     114        5325 :                                 assert(status == outside_str);
     115             :                                 status = inside_str;
     116             :                         }
     117       18056 :                 } else if (next == ',') {
     118          11 :                         if (status == outside_str && schema_path[i + 1] == '"') {
     119             :                                 status = inside_str;
     120             :                                 i++; /* has to advance two positions */
     121           2 :                         } else if (status == inside_str) {
     122           2 :                                 if (bp == 1023)
     123           0 :                                         throw(SQL, "sql.schema_path", SQLSTATE(42000) "A schema has up to 1023 characters");
     124           2 :                                 next_schema[bp++] = ','; /* used inside a schema name */
     125           0 :                         } else if (status == outside_str) {
     126           0 :                                 throw(SQL, "sql.schema_path", SQLSTATE(42000) "The '\"' character is expected after the comma separator");
     127             :                         }
     128       18045 :                 } else if (status == inside_str) {
     129       18044 :                         if (bp == 1023)
     130           0 :                                 throw(SQL, "sql.schema_path", SQLSTATE(42000) "A schema has up to 1023 characters");
     131       18044 :                         if (bp == 0 && next == '%')
     132           0 :                                 throw(SQL, "sql.schema_path", SQLSTATE(42000) "The character '%%' is not allowed as the first schema character");
     133       18044 :                         next_schema[bp++] = next;
     134             :                 } else {
     135           1 :                         assert(status == outside_str);
     136           1 :                         throw(SQL, "sql.schema_path", SQLSTATE(42000) "A schema in the path must be within '\"'");
     137             :                 }
     138             :         }
     139        5323 :         if (status == inside_str)
     140           1 :                 throw(SQL, "sql.schema_path", SQLSTATE(42000) "A schema path cannot end inside inside a schema name");
     141             :         return MAL_SUCCEED;
     142             : }
     143             : 
     144             : static str
     145         268 : monet5_create_user(ptr _mvc, str user, str passwd, char enc, str fullname, sqlid schema_id, str schema_path, sqlid grantorid)
     146             : {
     147             :         mvc *m = (mvc *) _mvc;
     148         268 :         oid uid = 0;
     149             :         str ret, pwd;
     150             :         sqlid user_id;
     151         268 :         sql_schema *s = find_sql_schema(m->session->tr, "sys");
     152         268 :         sql_table *db_user_info = find_sql_table(m->session->tr, s, "db_user_info"), *auths = find_sql_table(m->session->tr, s, "auths");
     153         268 :         Client c = MCgetClient(m->clientid);
     154         268 :         sqlstore *store = m->session->tr->store;
     155             :         int log_res = 0;
     156             : 
     157         268 :         if (!schema_path)
     158         267 :                 schema_path = default_schema_path;
     159         268 :         if ((ret = parse_schema_path_str(m, schema_path, false)) != MAL_SUCCEED)
     160             :                 return ret;
     161             : 
     162         268 :         if (!enc) {
     163          76 :                 if (!(pwd = mcrypt_BackendSum(passwd, strlen(passwd))))
     164           0 :                         throw(MAL, "sql.create_user", SQLSTATE(42000) "Crypt backend hash not found");
     165             :         } else {
     166             :                 pwd = passwd;
     167             :         }
     168             : 
     169         268 :         user_id = store_next_oid(m->session->tr->store);
     170         268 :         if ((log_res = store->table_api.table_insert(m->session->tr, db_user_info, &user, &fullname, &schema_id, &schema_path))) {
     171           0 :                 if (!enc)
     172           0 :                         free(pwd);
     173           0 :                 throw(SQL, "sql.create_user", SQLSTATE(42000) "Create user failed%s", log_res == LOG_CONFLICT ? " due to conflict with another transaction" : "");
     174             :         }
     175         268 :         if ((log_res = store->table_api.table_insert(m->session->tr, auths, &user_id, &user, &grantorid))) {
     176           0 :                 if (!enc)
     177           0 :                         free(pwd);
     178           0 :                 throw(SQL, "sql.create_user", SQLSTATE(42000) "Create user failed%s", log_res == LOG_CONFLICT ? " due to conflict with another transaction" : "");
     179             :         }
     180             : 
     181             :         /* add the user to the M5 authorisation administration */
     182         268 :         oid grant_user = c->user;
     183         268 :         c->user = MAL_ADMIN;
     184         268 :         ret = AUTHaddUser(&uid, c, user, pwd);
     185         268 :         c->user = grant_user;
     186         268 :         if (!enc)
     187          76 :                 free(pwd);
     188             :         return ret;
     189             : }
     190             : 
     191             : static int
     192         370 : monet5_find_user(ptr mp, str user)
     193             : {
     194             :         BAT *uid, *nme;
     195             :         BUN p;
     196             :         mvc *m = (mvc *) mp;
     197         370 :         Client c = MCgetClient(m->clientid);
     198             :         str err;
     199             : 
     200         370 :         if ((err = AUTHgetUsers(&uid, &nme, c)) != MAL_SUCCEED) {
     201           9 :                 freeException(err);
     202           9 :                 return -1;
     203             :         }
     204         361 :         p = BUNfnd(nme, user);
     205         361 :         BBPunfix(uid->batCacheid);
     206         361 :         BBPunfix(nme->batCacheid);
     207             : 
     208             :         /* yeah, I would prefer to return something different too */
     209         361 :         return (p == BUN_NONE ? -1 : 1);
     210             : }
     211             : 
     212             : str
     213        3824 : db_users_wrap(Client cntxt, MalBlkPtr mb, MalStkPtr stk, InstrPtr pci)
     214             : {
     215        3824 :         bat *r = getArgReference_bat(stk, pci, 0);
     216             :         BAT *uid, *nme;
     217             :         str err;
     218             : 
     219             :         (void) mb;
     220        3824 :         if ((err = AUTHgetUsers(&uid, &nme, cntxt)) != MAL_SUCCEED)
     221             :                 return err;
     222        3824 :         BBPunfix(uid->batCacheid);
     223        3824 :         *r = nme->batCacheid;
     224        3824 :         BBPkeepref(*r);
     225        3824 :         return MAL_SUCCEED;
     226             : }
     227             : 
     228             : str
     229         217 : db_password_wrap(Client cntxt, MalBlkPtr mb, MalStkPtr stk, InstrPtr pci)
     230             : {
     231             :         (void) mb;
     232             : 
     233         217 :         if (stk->stk[pci->argv[0]].vtype == TYPE_bat) {
     234         217 :                 BAT *b = BATdescriptor(*getArgReference_bat(stk, pci, 1));
     235         217 :                 if (b == NULL)
     236           0 :                         throw(SQL, "sql.password", SQLSTATE(HY002) RUNTIME_OBJECT_MISSING);
     237         217 :                 BAT *bn = COLnew(b->hseqbase, TYPE_str, BATcount(b), TRANSIENT);
     238         217 :                 if (bn == NULL) {
     239           0 :                         BBPunfix(b->batCacheid);
     240           0 :                         throw(SQL, "sql.password", SQLSTATE(HY013) MAL_MALLOC_FAIL);
     241             :                 }
     242         217 :                 BATiter bi = bat_iterator(b);
     243             :                 BUN p, q;
     244         245 :                 BATloop(b, p, q) {
     245             :                         char *hash, *msg;
     246          28 :                         msg = AUTHgetPasswordHash(&hash, cntxt, BUNtvar(bi, p));
     247          28 :                         if (msg != MAL_SUCCEED) {
     248           0 :                                 bat_iterator_end(&bi);
     249           0 :                                 BBPunfix(b->batCacheid);
     250           0 :                                 BBPreclaim(bn);
     251           0 :                                 return msg;
     252             :                         }
     253          28 :                         if (BUNappend(bn, hash, false) != GDK_SUCCEED) {
     254           0 :                                 bat_iterator_end(&bi);
     255           0 :                                 BBPunfix(b->batCacheid);
     256           0 :                                 BBPreclaim(bn);
     257           0 :                                 GDKfree(hash);
     258           0 :                                 throw(SQL, "sql.password", SQLSTATE(HY013) MAL_MALLOC_FAIL);
     259             :                         }
     260          28 :                         GDKfree(hash);
     261             :                 }
     262         217 :                 bat_iterator_end(&bi);
     263         217 :                 BBPunfix(b->batCacheid);
     264         217 :                 BBPkeepref(bn->batCacheid);
     265         217 :                 *getArgReference_bat(stk, pci, 0) = bn->batCacheid;
     266         217 :                 return MAL_SUCCEED;
     267             :         }
     268           0 :         str *hash = getArgReference_str(stk, pci, 0);
     269           0 :         str *user = getArgReference_str(stk, pci, 1);
     270             : 
     271           0 :         return AUTHgetPasswordHash(hash, cntxt, *user);
     272             : }
     273             : 
     274             : static void
     275         186 : monet5_create_privileges(ptr _mvc, sql_schema *s)
     276             : {
     277             :         sql_schema *sys;
     278         186 :         sql_table *t = NULL, *uinfo = NULL;
     279         186 :         sql_column *col = NULL;
     280             :         mvc *m = (mvc *) _mvc;
     281         186 :         sqlid schema_id = 0;
     282             :         list *res, *ops;
     283         186 :         sql_func *f = NULL;
     284             : 
     285             :         /* create the authorisation related tables */
     286         186 :         mvc_create_table(&t, m, s, "db_user_info", tt_table, 1, SQL_PERSIST, 0, -1, 0);
     287         186 :         mvc_create_column_(&col, m, t, "name", "varchar", 1024);
     288         186 :         mvc_create_column_(&col, m, t, "fullname", "varchar", 2048);
     289         186 :         mvc_create_column_(&col, m, t, "default_schema", "int", 9);
     290         186 :         mvc_create_column_(&col, m, t, "schema_path", "clob", 0);
     291         186 :         uinfo = t;
     292             : 
     293         186 :         res = sa_list(m->sa);
     294         186 :         list_append(res, sql_create_arg(m->sa, "name", sql_bind_subtype(m->sa, "varchar", 2048, 0), ARG_OUT));
     295             : 
     296             :         /* add function */
     297         186 :         ops = sa_list(m->sa);
     298             :         /* following funcion returns a table (single column) of user names
     299             :            with the approriate scenario (sql) */
     300         186 :         mvc_create_func(&f, m, NULL, s, "db_users", ops, res, F_UNION, FUNC_LANG_SQL, "sql", "db_users", "CREATE FUNCTION db_users () RETURNS TABLE( name varchar(2048)) EXTERNAL NAME sql.db_users;", FALSE, FALSE, TRUE);
     301             : 
     302         186 :         t = mvc_init_create_view(m, s, "users",
     303             :                             "create view sys.users as select u.\"name\" as \"name\", "
     304             :                             "ui.\"fullname\", ui.\"default_schema\", "
     305             :                                 "ui.\"schema_path\" from sys.db_users() as u "
     306             :                                 "left join \"sys\".\"db_user_info\" as ui "
     307             :                             "on u.\"name\" = ui.\"name\";");
     308         186 :         if (!t) {
     309           0 :                 TRC_CRITICAL(SQL_TRANS, "Failed to create 'users' view\n");
     310           0 :                 return ;
     311             :         }
     312             : 
     313         186 :         mvc_create_column_(&col, m, t, "name", "varchar", 2048);
     314         186 :         mvc_create_column_(&col, m, t, "fullname", "varchar", 2048);
     315         186 :         mvc_create_column_(&col, m, t, "default_schema", "int", 9);
     316         186 :         mvc_create_column_(&col, m, t, "schema_path", "clob", 0);
     317             : 
     318         186 :         sys = find_sql_schema(m->session->tr, "sys");
     319         186 :         schema_id = sys->base.id;
     320         186 :         assert(schema_id >= 0);
     321             : 
     322         186 :         sqlstore *store = m->session->tr->store;
     323         186 :         char *username = "monetdb";
     324         186 :         char *fullname = "MonetDB Admin";
     325         186 :         char *schema_path = default_schema_path;
     326         186 :         store->table_api.table_insert(m->session->tr, uinfo, &username, &fullname, &schema_id, &schema_path);
     327             : }
     328             : 
     329             : static int
     330         139 : monet5_schema_has_user(ptr _mvc, sql_schema *s)
     331             : {
     332             :         mvc *m = (mvc *) _mvc;
     333             :         oid rid;
     334         139 :         sql_schema *sys = find_sql_schema(m->session->tr, "sys");
     335         139 :         sql_table *users = find_sql_table(m->session->tr, sys, "db_user_info");
     336         139 :         sql_column *users_schema = find_sql_column(users, "default_schema");
     337         139 :         sqlid schema_id = s->base.id;
     338             : 
     339         139 :         sqlstore *store = m->session->tr->store;
     340         139 :         rid = store->table_api.column_find_row(m->session->tr, users_schema, &schema_id, NULL);
     341         139 :         if (is_oid_nil(rid))
     342         135 :                 return FALSE;
     343             :         return TRUE;
     344             : }
     345             : 
     346             : static int
     347          57 : monet5_alter_user(ptr _mvc, str user, str passwd, char enc, sqlid schema_id, str schema_path, str oldpasswd)
     348             : {
     349             :         mvc *m = (mvc *) _mvc;
     350          57 :         Client c = MCgetClient(m->clientid);
     351             :         str err;
     352             :         int res = LOG_OK;
     353             : 
     354          57 :         if (passwd != NULL) {
     355             :                 str pwd = NULL;
     356             :                 str opwd = NULL;
     357           4 :                 if (!enc) {
     358           4 :                         pwd = mcrypt_BackendSum(passwd, strlen(passwd));
     359           4 :                         if (pwd == NULL) {
     360           0 :                                 (void) sql_error(m, 02, SQLSTATE(42000) "ALTER USER: crypt backend hash not found");
     361           0 :                                 return FALSE;
     362             :                         }
     363           4 :                         if (oldpasswd != NULL) {
     364           2 :                                 opwd = mcrypt_BackendSum(oldpasswd, strlen(oldpasswd));
     365           2 :                                 if (opwd == NULL) {
     366           0 :                                         free(pwd);
     367           0 :                                         (void) sql_error(m, 02, SQLSTATE(42000) "ALTER USER: crypt backend hash not found");
     368           0 :                                         return FALSE;
     369             :                                 }
     370             :                         }
     371             :                 } else {
     372             :                         pwd = passwd;
     373             :                         opwd = oldpasswd;
     374             :                 }
     375           4 :                 if (user == NULL) {
     376           2 :                         err = AUTHchangePassword(c, opwd, pwd);
     377           2 :                         if (!enc) {
     378           2 :                                 free(pwd);
     379           2 :                                 free(opwd);
     380             :                         }
     381           2 :                         if (err !=MAL_SUCCEED) {
     382           1 :                                 (void) sql_error(m, 02, "ALTER USER: %s", getExceptionMessage(err));
     383           1 :                                 freeException(err);
     384           1 :                                 return (FALSE);
     385             :                         }
     386             :                 } else {
     387           2 :                         str username = NULL;
     388           2 :                         if ((err = AUTHresolveUser(&username, c->user)) !=MAL_SUCCEED) {
     389           0 :                                 if (!enc) {
     390           0 :                                         free(pwd);
     391           0 :                                         free(opwd);
     392             :                                 }
     393           0 :                                 (void) sql_error(m, 02, "ALTER USER: %s", getExceptionMessage(err));
     394           0 :                                 freeException(err);
     395           0 :                                 return (FALSE);
     396             :                         }
     397           2 :                         if (strcmp(username, user) == 0) {
     398             :                                 /* avoid message about changePassword (from MAL level) */
     399           0 :                                 GDKfree(username);
     400           0 :                                 if (!enc) {
     401           0 :                                         free(pwd);
     402           0 :                                         free(opwd);
     403             :                                 }
     404           0 :                                 (void) sql_error(m, 02, "ALTER USER: "
     405             :                                         "use 'ALTER USER SET [ ENCRYPTED ] PASSWORD xxx "
     406             :                                         "USING OLD PASSWORD yyy' "
     407             :                                         "when changing your own password");
     408           0 :                                 return (FALSE);
     409             :                         }
     410           2 :                         GDKfree(username);
     411           2 :                         err = AUTHsetPassword(c, user, pwd);
     412           2 :                         if (!enc) {
     413           2 :                                 free(pwd);
     414           2 :                                 free(opwd);
     415             :                         }
     416           2 :                         if (err !=MAL_SUCCEED) {
     417           0 :                                 (void) sql_error(m, 02, "ALTER USER: %s", getExceptionMessage(err));
     418           0 :                                 freeException(err);
     419           0 :                                 return (FALSE);
     420             :                         }
     421             :                 }
     422             :         }
     423             : 
     424          56 :         sqlstore *store = m->session->tr->store;
     425          56 :         if (schema_id) {
     426          46 :                 sql_schema *sys = find_sql_schema(m->session->tr, "sys");
     427          46 :                 sql_table *info = find_sql_table(m->session->tr, sys, "db_user_info");
     428          46 :                 sql_column *users_name = find_sql_column(info, "name");
     429          46 :                 sql_column *users_schema = find_sql_column(info, "default_schema");
     430             : 
     431          46 :                 oid rid = store->table_api.column_find_row(m->session->tr, users_name, user, NULL);
     432          46 :                 if (is_oid_nil(rid)) {
     433           1 :                         (void) sql_error(m, 02, "ALTER USER: local inconsistency, "
     434             :                                  "your database is damaged, auth not found in SQL catalog");
     435           1 :                         return FALSE;
     436             :                 }
     437          45 :                 if ((res = store->table_api.column_update_value(m->session->tr, users_schema, rid, &schema_id))) {
     438           0 :                         (void) sql_error(m, 02, SQLSTATE(42000) "ALTER USER: failed%s",
     439             :                                                         res == LOG_CONFLICT ? " due to conflict with another transaction" : "");
     440           0 :                         return (FALSE);
     441             :                 }
     442             :         }
     443             : 
     444          55 :         if (schema_path) {
     445           7 :                 sql_schema *sys = find_sql_schema(m->session->tr, "sys");
     446           7 :                 sql_table *info = find_sql_table(m->session->tr, sys, "db_user_info");
     447           7 :                 sql_column *users_name = find_sql_column(info, "name");
     448           7 :                 sql_column *sp = find_sql_column(info, "schema_path");
     449             : 
     450           7 :                 if ((err = parse_schema_path_str(m, schema_path, false)) != MAL_SUCCEED) {
     451           4 :                         (void) sql_error(m, 02, "ALTER USER: %s", getExceptionMessage(err));
     452           4 :                         freeException(err);
     453           4 :                         return (FALSE);
     454             :                 }
     455             : 
     456           3 :                 oid rid = store->table_api.column_find_row(m->session->tr, users_name, user, NULL);
     457           3 :                 if (is_oid_nil(rid)) {
     458           0 :                         (void) sql_error(m, 02, "ALTER USER: local inconsistency, "
     459             :                                  "your database is damaged, auth not found in SQL catalog");
     460           0 :                         return FALSE;
     461             :                 }
     462           3 :                 if ((res = store->table_api.column_update_value(m->session->tr, sp, rid, schema_path))) {
     463           0 :                         (void) sql_error(m, 02, SQLSTATE(42000) "ALTER USER: failed%s",
     464             :                                                         res == LOG_CONFLICT ? " due to conflict with another transaction" : "");
     465           0 :                         return (FALSE);
     466             :                 }
     467             :         }
     468             : 
     469             :         return TRUE;
     470             : }
     471             : 
     472             : static int
     473           2 : monet5_rename_user(ptr _mvc, str olduser, str newuser)
     474             : {
     475             :         mvc *m = (mvc *) _mvc;
     476           2 :         Client c = MCgetClient(m->clientid);
     477             :         str err;
     478             :         oid rid;
     479           2 :         sql_schema *sys = find_sql_schema(m->session->tr, "sys");
     480           2 :         sql_table *info = find_sql_table(m->session->tr, sys, "db_user_info");
     481           2 :         sql_column *users_name = find_sql_column(info, "name");
     482           2 :         sql_table *auths = find_sql_table(m->session->tr, sys, "auths");
     483           2 :         sql_column *auths_name = find_sql_column(auths, "name");
     484             :         int res = LOG_OK;
     485             : 
     486           2 :         if ((err = AUTHchangeUsername(c, olduser, newuser)) !=MAL_SUCCEED) {
     487           0 :                 (void) sql_error(m, 02, "ALTER USER: %s", getExceptionMessage(err));
     488           0 :                 freeException(err);
     489           0 :                 return (FALSE);
     490             :         }
     491             : 
     492           2 :         sqlstore *store = m->session->tr->store;
     493           2 :         rid = store->table_api.column_find_row(m->session->tr, users_name, olduser, NULL);
     494           2 :         if (is_oid_nil(rid)) {
     495           0 :                 (void) sql_error(m, 02, "ALTER USER: local inconsistency, "
     496             :                                  "your database is damaged, user not found in SQL catalog");
     497           0 :                 return (FALSE);
     498             :         }
     499           2 :         if ((res = store->table_api.column_update_value(m->session->tr, users_name, rid, newuser))) {
     500           0 :                 (void) sql_error(m, 02, SQLSTATE(42000) "ALTER USER: failed%s",
     501             :                                                  res == LOG_CONFLICT ? " due to conflict with another transaction" : "");
     502           0 :                 return (FALSE);
     503             :         }
     504             : 
     505           2 :         rid = store->table_api.column_find_row(m->session->tr, auths_name, olduser, NULL);
     506           2 :         if (is_oid_nil(rid)) {
     507           0 :                 (void) sql_error(m, 02, "ALTER USER: local inconsistency, "
     508             :                                  "your database is damaged, auth not found in SQL catalog");
     509           0 :                 return (FALSE);
     510             :         }
     511           2 :         if ((res = store->table_api.column_update_value(m->session->tr, auths_name, rid, newuser))) {
     512           0 :                 (void) sql_error(m, 02, SQLSTATE(42000) "ALTER USER: failed%s",
     513             :                                                  res == LOG_CONFLICT ? " due to conflict with another transaction" : "");
     514           0 :                 return (FALSE);
     515             :         }
     516             :         return (TRUE);
     517             : }
     518             : 
     519             : static void *
     520           0 : monet5_schema_user_dependencies(ptr _trans, int schema_id)
     521             : {
     522             :         rids *A, *U;
     523             :         sql_trans *tr = (sql_trans *) _trans;
     524           0 :         sql_schema *s = find_sql_schema(tr, "sys");
     525             : 
     526           0 :         sql_table *auths = find_sql_table(tr, s, "auths");
     527           0 :         sql_column *auth_name = find_sql_column(auths, "name");
     528             : 
     529           0 :         sql_table *users = find_sql_table(tr, s, "db_user_info");
     530           0 :         sql_column *users_name = find_sql_column(users, "name");
     531           0 :         sql_column *users_sch = find_sql_column(users, "default_schema");
     532             : 
     533           0 :         sqlstore *store = tr->store;
     534             :         /* select users with given schema */
     535           0 :         U = store->table_api.rids_select(tr, users_sch, &schema_id, &schema_id, NULL);
     536             :         /* select all authorization ids */
     537           0 :         A = store->table_api.rids_select(tr, auth_name, NULL, NULL);
     538             :         /* join all authorization with the selected users */
     539           0 :         A = store->table_api.rids_join(tr, A, auth_name, U, users_name);
     540           0 :         store->table_api.rids_destroy(U);
     541           0 :         return A;
     542             : }
     543             : 
     544             : void
     545         266 : monet5_user_init(backend_functions *be_funcs)
     546             : {
     547         266 :         be_funcs->fcuser = &monet5_create_user;
     548         266 :         be_funcs->fduser = &monet5_drop_user;
     549         266 :         be_funcs->ffuser = &monet5_find_user;
     550         266 :         be_funcs->fcrpriv = &monet5_create_privileges;
     551         266 :         be_funcs->fshuser = &monet5_schema_has_user;
     552         266 :         be_funcs->fauser = &monet5_alter_user;
     553         266 :         be_funcs->fruser = &monet5_rename_user;
     554         266 :         be_funcs->fschuserdep = &monet5_schema_user_dependencies;
     555         266 : }
     556             : 
     557             : int
     558           0 : monet5_user_get_def_schema(mvc *m, int user, str *schema)
     559             : {
     560             :         oid rid;
     561           0 :         sqlid schema_id = int_nil;
     562             :         sql_schema *sys = NULL;
     563             :         sql_table *user_info = NULL;
     564             :         sql_table *schemas = NULL;
     565             :         sql_table *auths = NULL;
     566             :         str username = NULL, sname = NULL;
     567           0 :         sqlstore *store = m->session->tr->store;
     568             : 
     569           0 :         sys = find_sql_schema(m->session->tr, "sys");
     570           0 :         auths = find_sql_table(m->session->tr, sys, "auths");
     571           0 :         user_info = find_sql_table(m->session->tr, sys, "db_user_info");
     572           0 :         schemas = find_sql_table(m->session->tr, sys, "schemas");
     573             : 
     574           0 :         rid = store->table_api.column_find_row(m->session->tr, find_sql_column(auths, "id"), &user, NULL);
     575           0 :         if (is_oid_nil(rid))
     576             :                 return -2;
     577           0 :         if (!(username = store->table_api.column_find_value(m->session->tr, find_sql_column(auths, "name"), rid)))
     578             :                 return -1;
     579           0 :         rid = store->table_api.column_find_row(m->session->tr, find_sql_column(user_info, "name"), username, NULL);
     580           0 :         _DELETE(username);
     581             : 
     582           0 :         if (!is_oid_nil(rid))
     583           0 :                 schema_id = store->table_api.column_find_sqlid(m->session->tr, find_sql_column(user_info, "default_schema"), rid);
     584           0 :         if (is_int_nil(schema_id))
     585             :                 return -3;
     586           0 :         rid = store->table_api.column_find_row(m->session->tr, find_sql_column(schemas, "id"), &schema_id, NULL);
     587           0 :         if (is_oid_nil(rid))
     588             :                 return -3;
     589             : 
     590           0 :         if (!(sname = store->table_api.column_find_value(m->session->tr, find_sql_column(schemas, "name"), rid)))
     591             :                 return -1;
     592           0 :         *schema = sa_strdup(m->session->sa, sname);
     593           0 :         _DELETE(sname);
     594           0 :         return *schema ? 0 : -1;
     595             : }
     596             : 
     597             : int
     598        5052 : monet5_user_set_def_schema(mvc *m, oid user)
     599             : {
     600             :         oid rid;
     601             :         sqlid schema_id;
     602             :         sql_schema *sys = NULL;
     603             :         sql_table *user_info = NULL;
     604             :         sql_column *users_name = NULL;
     605             :         sql_column *users_schema = NULL;
     606             :         sql_column *users_schema_path = NULL;
     607             :         sql_table *schemas = NULL;
     608             :         sql_column *schemas_name = NULL;
     609             :         sql_column *schemas_id = NULL;
     610             :         sql_table *auths = NULL;
     611             :         sql_column *auths_id = NULL;
     612             :         sql_column *auths_name = NULL;
     613        5052 :         str path_err = NULL, other = NULL, schema = NULL, schema_cpy, schema_path = NULL, username = NULL, err = NULL;
     614             :         int ok = 1, res = 0;
     615             : 
     616        5052 :         TRC_DEBUG(SQL_TRANS, OIDFMT "\n", user);
     617             : 
     618        5052 :         if ((err = AUTHresolveUser(&username, user)) != MAL_SUCCEED) {
     619           0 :                 freeException(err);
     620           0 :                 return -1;
     621             :         }
     622             : 
     623        5052 :         if ((res = mvc_trans(m)) < 0) {
     624           0 :                 GDKfree(username);
     625           0 :                 return res;
     626             :         }
     627             : 
     628        5052 :         sys = find_sql_schema(m->session->tr, "sys");
     629        5052 :         user_info = find_sql_table(m->session->tr, sys, "db_user_info");
     630        5052 :         users_name = find_sql_column(user_info, "name");
     631        5052 :         users_schema = find_sql_column(user_info, "default_schema");
     632        5052 :         users_schema_path = find_sql_column(user_info, "schema_path");
     633             : 
     634        5052 :         sqlstore *store = m->session->tr->store;
     635        5052 :         rid = store->table_api.column_find_row(m->session->tr, users_name, username, NULL);
     636        5052 :         if (is_oid_nil(rid)) {
     637           1 :                 if (m->session->tr->active && (other = mvc_rollback(m, 0, NULL, false)) != MAL_SUCCEED)
     638           0 :                         freeException(other);
     639           1 :                 GDKfree(username);
     640           1 :                 return -2;
     641             :         }
     642        5051 :         schema_id = store->table_api.column_find_sqlid(m->session->tr, users_schema, rid);
     643        5051 :         if (!(schema_path = store->table_api.column_find_value(m->session->tr, users_schema_path, rid))) {
     644           0 :                 if (m->session->tr->active && (other = mvc_rollback(m, 0, NULL, false)) != MAL_SUCCEED)
     645           0 :                         freeException(other);
     646           0 :                 GDKfree(username);
     647           0 :                 return -1;
     648             :         }
     649             : 
     650        5051 :         schemas = find_sql_table(m->session->tr, sys, "schemas");
     651        5051 :         schemas_name = find_sql_column(schemas, "name");
     652        5051 :         schemas_id = find_sql_column(schemas, "id");
     653        5051 :         auths = find_sql_table(m->session->tr, sys, "auths");
     654        5051 :         auths_id = find_sql_column(auths, "id");
     655        5051 :         auths_name = find_sql_column(auths, "name");
     656             : 
     657        5051 :         rid = store->table_api.column_find_row(m->session->tr, schemas_id, &schema_id, NULL);
     658        5051 :         if (is_oid_nil(rid)) {
     659           0 :                 if (m->session->tr->active && (other = mvc_rollback(m, 0, NULL, false)) != MAL_SUCCEED)
     660           0 :                         freeException(other);
     661           0 :                 GDKfree(username);
     662           0 :                 _DELETE(schema_path);
     663           0 :                 return -3;
     664             :         }
     665        5051 :         if (!(schema = store->table_api.column_find_value(m->session->tr, schemas_name, rid))) {
     666           0 :                 if (m->session->tr->active && (other = mvc_rollback(m, 0, NULL, false)) != MAL_SUCCEED)
     667           0 :                         freeException(other);
     668           0 :                 GDKfree(username);
     669           0 :                 _DELETE(schema_path);
     670           0 :                 return -1;
     671             :         }
     672             :         schema_cpy = schema;
     673        5051 :         schema = sa_strdup(m->session->sa, schema);
     674        5051 :         _DELETE(schema_cpy);
     675             : 
     676             :         /* check if username exists */
     677        5051 :         rid = store->table_api.column_find_row(m->session->tr, auths_name, username, NULL);
     678        5051 :         if (is_oid_nil(rid)) {
     679           0 :                 if (m->session->tr->active && (other = mvc_rollback(m, 0, NULL, false)) != MAL_SUCCEED)
     680           0 :                         freeException(other);
     681           0 :                 GDKfree(username);
     682           0 :                 _DELETE(schema_path);
     683           0 :                 return -2;
     684             :         }
     685        5051 :         m->user_id = m->role_id = store->table_api.column_find_sqlid(m->session->tr, auths_id, rid);
     686             : 
     687             :         /* while getting the session's schema, set the search path as well */
     688        5051 :         if (!(ok = mvc_set_schema(m, schema)) || (path_err = parse_schema_path_str(m, schema_path, true)) != MAL_SUCCEED) {
     689           0 :                 if (m->session->tr->active && (other = mvc_rollback(m, 0, NULL, false)) != MAL_SUCCEED)
     690           0 :                         freeException(other);
     691           0 :                 GDKfree(username);
     692           0 :                 _DELETE(schema_path);
     693           0 :                 freeException(path_err);
     694           0 :                 return ok == 0 ? -3 : -1;
     695             :         }
     696             : 
     697             :         /* reset the user and schema names */
     698       10102 :         if (!sqlvar_set_string(find_global_var(m, sys, "current_schema"), schema) ||
     699       10102 :                 !sqlvar_set_string(find_global_var(m, sys, "current_user"), username) ||
     700        5051 :                 !sqlvar_set_string(find_global_var(m, sys, "current_role"), username)) {
     701             :                 res = -1;
     702             :         }
     703        5051 :         GDKfree(username);
     704        5051 :         _DELETE(schema_path);
     705        5051 :         if ((other = mvc_rollback(m, 0, NULL, false)) != MAL_SUCCEED) {
     706           0 :                 freeException(other);
     707           0 :                 return -1;
     708             :         }
     709             :         return res;
     710             : }

Generated by: LCOV version 1.14