Header And Logo

PostgreSQL
| The world's most advanced open source database.

Functions | Variables

user.c File Reference

#include "postgres.h"
#include "access/genam.h"
#include "access/heapam.h"
#include "access/htup_details.h"
#include "access/xact.h"
#include "catalog/dependency.h"
#include "catalog/indexing.h"
#include "catalog/objectaccess.h"
#include "catalog/pg_auth_members.h"
#include "catalog/pg_authid.h"
#include "catalog/pg_database.h"
#include "catalog/pg_db_role_setting.h"
#include "commands/comment.h"
#include "commands/dbcommands.h"
#include "commands/seclabel.h"
#include "commands/user.h"
#include "libpq/md5.h"
#include "miscadmin.h"
#include "storage/lmgr.h"
#include "utils/acl.h"
#include "utils/builtins.h"
#include "utils/fmgroids.h"
#include "utils/syscache.h"
#include "utils/timestamp.h"
#include "utils/tqual.h"
Include dependency graph for user.c:

Go to the source code of this file.

Functions

static ListroleNamesToIds (List *memberNames)
static void AddRoleMems (const char *rolename, Oid roleid, List *memberNames, List *memberIds, Oid grantorId, bool admin_opt)
static void DelRoleMems (const char *rolename, Oid roleid, List *memberNames, List *memberIds, bool admin_opt)
static bool have_createrole_privilege (void)
Oid CreateRole (CreateRoleStmt *stmt)
Oid AlterRole (AlterRoleStmt *stmt)
Oid AlterRoleSet (AlterRoleSetStmt *stmt)
void DropRole (DropRoleStmt *stmt)
Oid RenameRole (const char *oldname, const char *newname)
void GrantRole (GrantRoleStmt *stmt)
void DropOwnedObjects (DropOwnedStmt *stmt)
void ReassignOwnedObjects (ReassignOwnedStmt *stmt)

Variables

Oid binary_upgrade_next_pg_authid_oid = InvalidOid
bool Password_encryption
check_password_hook_type check_password_hook = NULL

Function Documentation

static void AddRoleMems ( const char *  rolename,
Oid  roleid,
List memberNames,
List memberIds,
Oid  grantorId,
bool  admin_opt 
) [static]

Definition at line 1333 of file user.c.

References Anum_pg_auth_members_admin_option, Anum_pg_auth_members_grantor, Anum_pg_auth_members_member, Anum_pg_auth_members_roleid, Assert, AuthMemRelationId, AUTHMEMROLEMEM, BoolGetDatum, CatalogUpdateIndexes(), CommandCounterIncrement(), ereport, errcode(), errmsg(), ERROR, forboth, GETSTRUCT, GetUserId(), have_createrole_privilege(), heap_close, heap_form_tuple(), heap_modify_tuple(), heap_open(), HeapTupleIsValid, is_admin_of_role(), is_member_of_role_nosuper(), lfirst, lfirst_oid, list_length(), MemSet, NoLock, NOTICE, ObjectIdGetDatum, RelationGetDescr, ReleaseSysCache(), RowExclusiveLock, SearchSysCache2, simple_heap_insert(), simple_heap_update(), strVal, superuser(), superuser_arg(), and HeapTupleData::t_self.

Referenced by AlterRole(), CreateRole(), and GrantRole().

{
    Relation    pg_authmem_rel;
    TupleDesc   pg_authmem_dsc;
    ListCell   *nameitem;
    ListCell   *iditem;

    Assert(list_length(memberNames) == list_length(memberIds));

    /* Skip permission check if nothing to do */
    if (!memberIds)
        return;

    /*
     * Check permissions: must have createrole or admin option on the role to
     * be changed.  To mess with a superuser role, you gotta be superuser.
     */
    if (superuser_arg(roleid))
    {
        if (!superuser())
            ereport(ERROR,
                    (errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
                     errmsg("must be superuser to alter superusers")));
    }
    else
    {
        if (!have_createrole_privilege() &&
            !is_admin_of_role(grantorId, roleid))
            ereport(ERROR,
                    (errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
                     errmsg("must have admin option on role \"%s\"",
                            rolename)));
    }

    /* XXX not sure about this check */
    if (grantorId != GetUserId() && !superuser())
        ereport(ERROR,
                (errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
                 errmsg("must be superuser to set grantor")));

    pg_authmem_rel = heap_open(AuthMemRelationId, RowExclusiveLock);
    pg_authmem_dsc = RelationGetDescr(pg_authmem_rel);

    forboth(nameitem, memberNames, iditem, memberIds)
    {
        const char *membername = strVal(lfirst(nameitem));
        Oid         memberid = lfirst_oid(iditem);
        HeapTuple   authmem_tuple;
        HeapTuple   tuple;
        Datum       new_record[Natts_pg_auth_members];
        bool        new_record_nulls[Natts_pg_auth_members];
        bool        new_record_repl[Natts_pg_auth_members];

        /*
         * Refuse creation of membership loops, including the trivial case
         * where a role is made a member of itself.  We do this by checking to
         * see if the target role is already a member of the proposed member
         * role.  We have to ignore possible superuserness, however, else we
         * could never grant membership in a superuser-privileged role.
         */
        if (is_member_of_role_nosuper(roleid, memberid))
            ereport(ERROR,
                    (errcode(ERRCODE_INVALID_GRANT_OPERATION),
                     (errmsg("role \"%s\" is a member of role \"%s\"",
                             rolename, membername))));

        /*
         * Check if entry for this role/member already exists; if so, give
         * warning unless we are adding admin option.
         */
        authmem_tuple = SearchSysCache2(AUTHMEMROLEMEM,
                                        ObjectIdGetDatum(roleid),
                                        ObjectIdGetDatum(memberid));
        if (HeapTupleIsValid(authmem_tuple) &&
            (!admin_opt ||
             ((Form_pg_auth_members) GETSTRUCT(authmem_tuple))->admin_option))
        {
            ereport(NOTICE,
                    (errmsg("role \"%s\" is already a member of role \"%s\"",
                            membername, rolename)));
            ReleaseSysCache(authmem_tuple);
            continue;
        }

        /* Build a tuple to insert or update */
        MemSet(new_record, 0, sizeof(new_record));
        MemSet(new_record_nulls, false, sizeof(new_record_nulls));
        MemSet(new_record_repl, false, sizeof(new_record_repl));

        new_record[Anum_pg_auth_members_roleid - 1] = ObjectIdGetDatum(roleid);
        new_record[Anum_pg_auth_members_member - 1] = ObjectIdGetDatum(memberid);
        new_record[Anum_pg_auth_members_grantor - 1] = ObjectIdGetDatum(grantorId);
        new_record[Anum_pg_auth_members_admin_option - 1] = BoolGetDatum(admin_opt);

        if (HeapTupleIsValid(authmem_tuple))
        {
            new_record_repl[Anum_pg_auth_members_grantor - 1] = true;
            new_record_repl[Anum_pg_auth_members_admin_option - 1] = true;
            tuple = heap_modify_tuple(authmem_tuple, pg_authmem_dsc,
                                      new_record,
                                      new_record_nulls, new_record_repl);
            simple_heap_update(pg_authmem_rel, &tuple->t_self, tuple);
            CatalogUpdateIndexes(pg_authmem_rel, tuple);
            ReleaseSysCache(authmem_tuple);
        }
        else
        {
            tuple = heap_form_tuple(pg_authmem_dsc,
                                    new_record, new_record_nulls);
            simple_heap_insert(pg_authmem_rel, tuple);
            CatalogUpdateIndexes(pg_authmem_rel, tuple);
        }

        /* CCI after each change, in case there are duplicates in list */
        CommandCounterIncrement();
    }

    /*
     * Close pg_authmem, but keep lock till commit.
     */
    heap_close(pg_authmem_rel, NoLock);
}

Oid AlterRole ( AlterRoleStmt stmt  ) 

Definition at line 448 of file user.c.

References AlterRoleStmt::action, AddRoleMems(), Anum_pg_authid_rolcanlogin, Anum_pg_authid_rolcatupdate, Anum_pg_authid_rolconnlimit, Anum_pg_authid_rolcreatedb, Anum_pg_authid_rolcreaterole, Anum_pg_authid_rolinherit, Anum_pg_authid_rolpassword, Anum_pg_authid_rolreplication, Anum_pg_authid_rolsuper, Anum_pg_authid_rolvaliduntil, DefElem::arg, AuthIdRelationId, AUTHNAME, BoolGetDatum, CatalogUpdateIndexes(), check_password_hook, CommandCounterIncrement(), createdb(), CStringGetDatum, CStringGetTextDatum, DefElem::defname, DelRoleMems(), DirectFunctionCall3, elog, ereport, errcode(), errmsg(), ERROR, GETSTRUCT, GetUserId(), have_createrole_privilege(), heap_close, heap_freetuple(), heap_modify_tuple(), heap_open(), HeapTupleGetOid, HeapTupleIsValid, Int32GetDatum, intVal, InvalidOid, InvokeObjectPostAlterHook, isMD5, lfirst, MD5_PASSWD_LEN, MemSet, NoLock, NULL, ObjectIdGetDatum, AlterRoleStmt::options, Password_encryption, PASSWORD_TYPE_MD5, pg_md5_encrypt(), PointerGetDatum, RelationGetDescr, ReleaseSysCache(), AlterRoleStmt::role, roleNamesToIds(), RowExclusiveLock, SearchSysCache1, simple_heap_update(), strVal, superuser(), SysCacheGetAttr(), HeapTupleData::t_self, and timestamptz_in().

Referenced by standard_ProcessUtility().

{
    Datum       new_record[Natts_pg_authid];
    bool        new_record_nulls[Natts_pg_authid];
    bool        new_record_repl[Natts_pg_authid];
    Relation    pg_authid_rel;
    TupleDesc   pg_authid_dsc;
    HeapTuple   tuple,
                new_tuple;
    ListCell   *option;
    char       *password = NULL;    /* user password */
    bool        encrypt_password = Password_encryption; /* encrypt password? */
    char        encrypted_password[MD5_PASSWD_LEN + 1];
    int         issuper = -1;   /* Make the user a superuser? */
    int         inherit = -1;   /* Auto inherit privileges? */
    int         createrole = -1;    /* Can this user create roles? */
    int         createdb = -1;  /* Can the user create databases? */
    int         canlogin = -1;  /* Can this user login? */
    int         isreplication = -1;     /* Is this a replication role? */
    int         connlimit = -1; /* maximum connections allowed */
    List       *rolemembers = NIL;      /* roles to be added/removed */
    char       *validUntil = NULL;      /* time the login is valid until */
    Datum       validUntil_datum;       /* same, as timestamptz Datum */
    bool        validUntil_null;
    DefElem    *dpassword = NULL;
    DefElem    *dissuper = NULL;
    DefElem    *dinherit = NULL;
    DefElem    *dcreaterole = NULL;
    DefElem    *dcreatedb = NULL;
    DefElem    *dcanlogin = NULL;
    DefElem    *disreplication = NULL;
    DefElem    *dconnlimit = NULL;
    DefElem    *drolemembers = NULL;
    DefElem    *dvalidUntil = NULL;
    Oid         roleid;

    /* Extract options from the statement node tree */
    foreach(option, stmt->options)
    {
        DefElem    *defel = (DefElem *) lfirst(option);

        if (strcmp(defel->defname, "password") == 0 ||
            strcmp(defel->defname, "encryptedPassword") == 0 ||
            strcmp(defel->defname, "unencryptedPassword") == 0)
        {
            if (dpassword)
                ereport(ERROR,
                        (errcode(ERRCODE_SYNTAX_ERROR),
                         errmsg("conflicting or redundant options")));
            dpassword = defel;
            if (strcmp(defel->defname, "encryptedPassword") == 0)
                encrypt_password = true;
            else if (strcmp(defel->defname, "unencryptedPassword") == 0)
                encrypt_password = false;
        }
        else if (strcmp(defel->defname, "superuser") == 0)
        {
            if (dissuper)
                ereport(ERROR,
                        (errcode(ERRCODE_SYNTAX_ERROR),
                         errmsg("conflicting or redundant options")));
            dissuper = defel;
        }
        else if (strcmp(defel->defname, "inherit") == 0)
        {
            if (dinherit)
                ereport(ERROR,
                        (errcode(ERRCODE_SYNTAX_ERROR),
                         errmsg("conflicting or redundant options")));
            dinherit = defel;
        }
        else if (strcmp(defel->defname, "createrole") == 0)
        {
            if (dcreaterole)
                ereport(ERROR,
                        (errcode(ERRCODE_SYNTAX_ERROR),
                         errmsg("conflicting or redundant options")));
            dcreaterole = defel;
        }
        else if (strcmp(defel->defname, "createdb") == 0)
        {
            if (dcreatedb)
                ereport(ERROR,
                        (errcode(ERRCODE_SYNTAX_ERROR),
                         errmsg("conflicting or redundant options")));
            dcreatedb = defel;
        }
        else if (strcmp(defel->defname, "canlogin") == 0)
        {
            if (dcanlogin)
                ereport(ERROR,
                        (errcode(ERRCODE_SYNTAX_ERROR),
                         errmsg("conflicting or redundant options")));
            dcanlogin = defel;
        }
        else if (strcmp(defel->defname, "isreplication") == 0)
        {
            if (disreplication)
                ereport(ERROR,
                        (errcode(ERRCODE_SYNTAX_ERROR),
                         errmsg("conflicting or redundant options")));
            disreplication = defel;
        }
        else if (strcmp(defel->defname, "connectionlimit") == 0)
        {
            if (dconnlimit)
                ereport(ERROR,
                        (errcode(ERRCODE_SYNTAX_ERROR),
                         errmsg("conflicting or redundant options")));
            dconnlimit = defel;
        }
        else if (strcmp(defel->defname, "rolemembers") == 0 &&
                 stmt->action != 0)
        {
            if (drolemembers)
                ereport(ERROR,
                        (errcode(ERRCODE_SYNTAX_ERROR),
                         errmsg("conflicting or redundant options")));
            drolemembers = defel;
        }
        else if (strcmp(defel->defname, "validUntil") == 0)
        {
            if (dvalidUntil)
                ereport(ERROR,
                        (errcode(ERRCODE_SYNTAX_ERROR),
                         errmsg("conflicting or redundant options")));
            dvalidUntil = defel;
        }
        else
            elog(ERROR, "option \"%s\" not recognized",
                 defel->defname);
    }

    if (dpassword && dpassword->arg)
        password = strVal(dpassword->arg);
    if (dissuper)
        issuper = intVal(dissuper->arg);
    if (dinherit)
        inherit = intVal(dinherit->arg);
    if (dcreaterole)
        createrole = intVal(dcreaterole->arg);
    if (dcreatedb)
        createdb = intVal(dcreatedb->arg);
    if (dcanlogin)
        canlogin = intVal(dcanlogin->arg);
    if (disreplication)
        isreplication = intVal(disreplication->arg);
    if (dconnlimit)
    {
        connlimit = intVal(dconnlimit->arg);
        if (connlimit < -1)
            ereport(ERROR,
                    (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
                     errmsg("invalid connection limit: %d", connlimit)));
    }
    if (drolemembers)
        rolemembers = (List *) drolemembers->arg;
    if (dvalidUntil)
        validUntil = strVal(dvalidUntil->arg);

    /*
     * Scan the pg_authid relation to be certain the user exists.
     */
    pg_authid_rel = heap_open(AuthIdRelationId, RowExclusiveLock);
    pg_authid_dsc = RelationGetDescr(pg_authid_rel);

    tuple = SearchSysCache1(AUTHNAME, PointerGetDatum(stmt->role));
    if (!HeapTupleIsValid(tuple))
        ereport(ERROR,
                (errcode(ERRCODE_UNDEFINED_OBJECT),
                 errmsg("role \"%s\" does not exist", stmt->role)));

    roleid = HeapTupleGetOid(tuple);

    /*
     * To mess with a superuser you gotta be superuser; else you need
     * createrole, or just want to change your own password
     */
    if (((Form_pg_authid) GETSTRUCT(tuple))->rolsuper || issuper >= 0)
    {
        if (!superuser())
            ereport(ERROR,
                    (errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
                     errmsg("must be superuser to alter superusers")));
    }
    else if (((Form_pg_authid) GETSTRUCT(tuple))->rolreplication || isreplication >= 0)
    {
        if (!superuser())
            ereport(ERROR,
                    (errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
                     errmsg("must be superuser to alter replication users")));
    }
    else if (!have_createrole_privilege())
    {
        if (!(inherit < 0 &&
              createrole < 0 &&
              createdb < 0 &&
              canlogin < 0 &&
              isreplication < 0 &&
              !dconnlimit &&
              !rolemembers &&
              !validUntil &&
              dpassword &&
              roleid == GetUserId()))
            ereport(ERROR,
                    (errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
                     errmsg("permission denied")));
    }

    /* Convert validuntil to internal form */
    if (validUntil)
    {
        validUntil_datum = DirectFunctionCall3(timestamptz_in,
                                               CStringGetDatum(validUntil),
                                               ObjectIdGetDatum(InvalidOid),
                                               Int32GetDatum(-1));
        validUntil_null = false;
    }
    else
    {
        /* fetch existing setting in case hook needs it */
        validUntil_datum = SysCacheGetAttr(AUTHNAME, tuple,
                                           Anum_pg_authid_rolvaliduntil,
                                           &validUntil_null);
    }

    /*
     * Call the password checking hook if there is one defined
     */
    if (check_password_hook && password)
        (*check_password_hook) (stmt->role,
                                password,
               isMD5(password) ? PASSWORD_TYPE_MD5 : PASSWORD_TYPE_PLAINTEXT,
                                validUntil_datum,
                                validUntil_null);

    /*
     * Build an updated tuple, perusing the information just obtained
     */
    MemSet(new_record, 0, sizeof(new_record));
    MemSet(new_record_nulls, false, sizeof(new_record_nulls));
    MemSet(new_record_repl, false, sizeof(new_record_repl));

    /*
     * issuper/createrole/catupdate/etc
     *
     * XXX It's rather unclear how to handle catupdate.  It's probably best to
     * keep it equal to the superuser status, otherwise you could end up with
     * a situation where no existing superuser can alter the catalogs,
     * including pg_authid!
     */
    if (issuper >= 0)
    {
        new_record[Anum_pg_authid_rolsuper - 1] = BoolGetDatum(issuper > 0);
        new_record_repl[Anum_pg_authid_rolsuper - 1] = true;

        new_record[Anum_pg_authid_rolcatupdate - 1] = BoolGetDatum(issuper > 0);
        new_record_repl[Anum_pg_authid_rolcatupdate - 1] = true;
    }

    if (inherit >= 0)
    {
        new_record[Anum_pg_authid_rolinherit - 1] = BoolGetDatum(inherit > 0);
        new_record_repl[Anum_pg_authid_rolinherit - 1] = true;
    }

    if (createrole >= 0)
    {
        new_record[Anum_pg_authid_rolcreaterole - 1] = BoolGetDatum(createrole > 0);
        new_record_repl[Anum_pg_authid_rolcreaterole - 1] = true;
    }

    if (createdb >= 0)
    {
        new_record[Anum_pg_authid_rolcreatedb - 1] = BoolGetDatum(createdb > 0);
        new_record_repl[Anum_pg_authid_rolcreatedb - 1] = true;
    }

    if (canlogin >= 0)
    {
        new_record[Anum_pg_authid_rolcanlogin - 1] = BoolGetDatum(canlogin > 0);
        new_record_repl[Anum_pg_authid_rolcanlogin - 1] = true;
    }

    if (isreplication >= 0)
    {
        new_record[Anum_pg_authid_rolreplication - 1] = BoolGetDatum(isreplication > 0);
        new_record_repl[Anum_pg_authid_rolreplication - 1] = true;
    }

    if (dconnlimit)
    {
        new_record[Anum_pg_authid_rolconnlimit - 1] = Int32GetDatum(connlimit);
        new_record_repl[Anum_pg_authid_rolconnlimit - 1] = true;
    }

    /* password */
    if (password)
    {
        if (!encrypt_password || isMD5(password))
            new_record[Anum_pg_authid_rolpassword - 1] =
                CStringGetTextDatum(password);
        else
        {
            if (!pg_md5_encrypt(password, stmt->role, strlen(stmt->role),
                                encrypted_password))
                elog(ERROR, "password encryption failed");
            new_record[Anum_pg_authid_rolpassword - 1] =
                CStringGetTextDatum(encrypted_password);
        }
        new_record_repl[Anum_pg_authid_rolpassword - 1] = true;
    }

    /* unset password */
    if (dpassword && dpassword->arg == NULL)
    {
        new_record_repl[Anum_pg_authid_rolpassword - 1] = true;
        new_record_nulls[Anum_pg_authid_rolpassword - 1] = true;
    }

    /* valid until */
    new_record[Anum_pg_authid_rolvaliduntil - 1] = validUntil_datum;
    new_record_nulls[Anum_pg_authid_rolvaliduntil - 1] = validUntil_null;
    new_record_repl[Anum_pg_authid_rolvaliduntil - 1] = true;

    new_tuple = heap_modify_tuple(tuple, pg_authid_dsc, new_record,
                                  new_record_nulls, new_record_repl);
    simple_heap_update(pg_authid_rel, &tuple->t_self, new_tuple);

    /* Update indexes */
    CatalogUpdateIndexes(pg_authid_rel, new_tuple);

    InvokeObjectPostAlterHook(AuthIdRelationId, roleid, 0);

    ReleaseSysCache(tuple);
    heap_freetuple(new_tuple);

    /*
     * Advance command counter so we can see new record; else tests in
     * AddRoleMems may fail.
     */
    if (rolemembers)
        CommandCounterIncrement();

    if (stmt->action == +1)     /* add members to role */
        AddRoleMems(stmt->role, roleid,
                    rolemembers, roleNamesToIds(rolemembers),
                    GetUserId(), false);
    else if (stmt->action == -1)    /* drop members from role */
        DelRoleMems(stmt->role, roleid,
                    rolemembers, roleNamesToIds(rolemembers),
                    false);

    /*
     * Close pg_authid, but keep lock till commit.
     */
    heap_close(pg_authid_rel, NoLock);

    return roleid;
}

Oid AlterRoleSet ( AlterRoleSetStmt stmt  ) 

Definition at line 814 of file user.c.

References ACL_KIND_DATABASE, aclcheck_error(), ACLCHECK_NOT_OWNER, AlterSetting(), AuthIdRelationId, AUTHNAME, AlterRoleSetStmt::database, DatabaseRelationId, ereport, errcode(), errmsg(), ERROR, get_database_oid(), GETSTRUCT, GetUserId(), have_createrole_privilege(), HeapTupleGetOid, HeapTupleIsValid, NULL, pg_database_ownercheck(), PointerGetDatum, ReleaseSysCache(), AlterRoleSetStmt::role, SearchSysCache1, AlterRoleSetStmt::setstmt, shdepLockAndCheckObject(), and superuser().

Referenced by standard_ProcessUtility().

{
    HeapTuple   roletuple;
    Oid         databaseid = InvalidOid;
    Oid         roleid = InvalidOid;

    if (stmt->role)
    {
        roletuple = SearchSysCache1(AUTHNAME, PointerGetDatum(stmt->role));

        if (!HeapTupleIsValid(roletuple))
            ereport(ERROR,
                    (errcode(ERRCODE_UNDEFINED_OBJECT),
                     errmsg("role \"%s\" does not exist", stmt->role)));

        roleid = HeapTupleGetOid(roletuple);

        /*
         * Obtain a lock on the role and make sure it didn't go away in the
         * meantime.
         */
        shdepLockAndCheckObject(AuthIdRelationId, HeapTupleGetOid(roletuple));

        /*
         * To mess with a superuser you gotta be superuser; else you need
         * createrole, or just want to change your own settings
         */
        if (((Form_pg_authid) GETSTRUCT(roletuple))->rolsuper)
        {
            if (!superuser())
                ereport(ERROR,
                        (errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
                         errmsg("must be superuser to alter superusers")));
        }
        else
        {
            if (!have_createrole_privilege() &&
                HeapTupleGetOid(roletuple) != GetUserId())
                ereport(ERROR,
                        (errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
                         errmsg("permission denied")));
        }

        ReleaseSysCache(roletuple);
    }

    /* look up and lock the database, if specified */
    if (stmt->database != NULL)
    {
        databaseid = get_database_oid(stmt->database, false);
        shdepLockAndCheckObject(DatabaseRelationId, databaseid);

        if (!stmt->role)
        {
            /*
             * If no role is specified, then this is effectively the same as
             * ALTER DATABASE ... SET, so use the same permission check.
             */
            if (!pg_database_ownercheck(databaseid, GetUserId()))
                aclcheck_error(ACLCHECK_NOT_OWNER, ACL_KIND_DATABASE,
                               stmt->database);
        }
    }

    if (!stmt->role && !stmt->database)
    {
        /* Must be superuser to alter settings globally. */
        if (!superuser())
            ereport(ERROR,
                    (errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
                     errmsg("must be superuser to alter settings globally")));
    }

    AlterSetting(databaseid, roleid, stmt->setstmt);

    return roleid;
}

Oid CreateRole ( CreateRoleStmt stmt  ) 

Definition at line 71 of file user.c.

References AddRoleMems(), Anum_pg_authid_rolcanlogin, Anum_pg_authid_rolcatupdate, Anum_pg_authid_rolconnlimit, Anum_pg_authid_rolcreatedb, Anum_pg_authid_rolcreaterole, Anum_pg_authid_rolinherit, Anum_pg_authid_rolname, Anum_pg_authid_rolpassword, Anum_pg_authid_rolreplication, Anum_pg_authid_rolsuper, Anum_pg_authid_rolvaliduntil, DefElem::arg, AuthIdRelationId, binary_upgrade_next_pg_authid_oid, BoolGetDatum, CatalogUpdateIndexes(), check_password_hook, CommandCounterIncrement(), createdb(), CStringGetDatum, CStringGetTextDatum, DefElem::defname, DirectFunctionCall1, DirectFunctionCall3, elog, ereport, errcode(), errmsg(), ERROR, get_role_oid(), GetUserId(), have_createrole_privilege(), heap_close, heap_form_tuple(), heap_open(), HeapTupleSetOid, Int32GetDatum, intVal, InvalidOid, InvokeObjectPostCreateHook, IsBinaryUpgrade, isMD5, lfirst, list_make1, list_make1_oid, makeString(), MD5_PASSWD_LEN, MemSet, namein(), NoLock, NOTICE, ObjectIdGetDatum, OidIsValid, CreateRoleStmt::options, Password_encryption, PASSWORD_TYPE_MD5, pg_md5_encrypt(), RelationGetDescr, CreateRoleStmt::role, roleNamesToIds(), ROLESTMT_GROUP, ROLESTMT_ROLE, ROLESTMT_USER, RowExclusiveLock, simple_heap_insert(), CreateRoleStmt::stmt_type, strVal, superuser(), and timestamptz_in().

Referenced by standard_ProcessUtility().

{
    Relation    pg_authid_rel;
    TupleDesc   pg_authid_dsc;
    HeapTuple   tuple;
    Datum       new_record[Natts_pg_authid];
    bool        new_record_nulls[Natts_pg_authid];
    Oid         roleid;
    ListCell   *item;
    ListCell   *option;
    char       *password = NULL;    /* user password */
    bool        encrypt_password = Password_encryption; /* encrypt password? */
    char        encrypted_password[MD5_PASSWD_LEN + 1];
    bool        issuper = false;    /* Make the user a superuser? */
    bool        inherit = true; /* Auto inherit privileges? */
    bool        createrole = false;     /* Can this user create roles? */
    bool        createdb = false;       /* Can the user create databases? */
    bool        canlogin = false;       /* Can this user login? */
    bool        isreplication = false;  /* Is this a replication role? */
    int         connlimit = -1; /* maximum connections allowed */
    List       *addroleto = NIL;    /* roles to make this a member of */
    List       *rolemembers = NIL;      /* roles to be members of this role */
    List       *adminmembers = NIL;     /* roles to be admins of this role */
    char       *validUntil = NULL;      /* time the login is valid until */
    Datum       validUntil_datum;       /* same, as timestamptz Datum */
    bool        validUntil_null;
    DefElem    *dpassword = NULL;
    DefElem    *dissuper = NULL;
    DefElem    *dinherit = NULL;
    DefElem    *dcreaterole = NULL;
    DefElem    *dcreatedb = NULL;
    DefElem    *dcanlogin = NULL;
    DefElem    *disreplication = NULL;
    DefElem    *dconnlimit = NULL;
    DefElem    *daddroleto = NULL;
    DefElem    *drolemembers = NULL;
    DefElem    *dadminmembers = NULL;
    DefElem    *dvalidUntil = NULL;

    /* The defaults can vary depending on the original statement type */
    switch (stmt->stmt_type)
    {
        case ROLESTMT_ROLE:
            break;
        case ROLESTMT_USER:
            canlogin = true;
            /* may eventually want inherit to default to false here */
            break;
        case ROLESTMT_GROUP:
            break;
    }

    /* Extract options from the statement node tree */
    foreach(option, stmt->options)
    {
        DefElem    *defel = (DefElem *) lfirst(option);

        if (strcmp(defel->defname, "password") == 0 ||
            strcmp(defel->defname, "encryptedPassword") == 0 ||
            strcmp(defel->defname, "unencryptedPassword") == 0)
        {
            if (dpassword)
                ereport(ERROR,
                        (errcode(ERRCODE_SYNTAX_ERROR),
                         errmsg("conflicting or redundant options")));
            dpassword = defel;
            if (strcmp(defel->defname, "encryptedPassword") == 0)
                encrypt_password = true;
            else if (strcmp(defel->defname, "unencryptedPassword") == 0)
                encrypt_password = false;
        }
        else if (strcmp(defel->defname, "sysid") == 0)
        {
            ereport(NOTICE,
                    (errmsg("SYSID can no longer be specified")));
        }
        else if (strcmp(defel->defname, "superuser") == 0)
        {
            if (dissuper)
                ereport(ERROR,
                        (errcode(ERRCODE_SYNTAX_ERROR),
                         errmsg("conflicting or redundant options")));
            dissuper = defel;
        }
        else if (strcmp(defel->defname, "inherit") == 0)
        {
            if (dinherit)
                ereport(ERROR,
                        (errcode(ERRCODE_SYNTAX_ERROR),
                         errmsg("conflicting or redundant options")));
            dinherit = defel;
        }
        else if (strcmp(defel->defname, "createrole") == 0)
        {
            if (dcreaterole)
                ereport(ERROR,
                        (errcode(ERRCODE_SYNTAX_ERROR),
                         errmsg("conflicting or redundant options")));
            dcreaterole = defel;
        }
        else if (strcmp(defel->defname, "createdb") == 0)
        {
            if (dcreatedb)
                ereport(ERROR,
                        (errcode(ERRCODE_SYNTAX_ERROR),
                         errmsg("conflicting or redundant options")));
            dcreatedb = defel;
        }
        else if (strcmp(defel->defname, "canlogin") == 0)
        {
            if (dcanlogin)
                ereport(ERROR,
                        (errcode(ERRCODE_SYNTAX_ERROR),
                         errmsg("conflicting or redundant options")));
            dcanlogin = defel;
        }
        else if (strcmp(defel->defname, "isreplication") == 0)
        {
            if (disreplication)
                ereport(ERROR,
                        (errcode(ERRCODE_SYNTAX_ERROR),
                         errmsg("conflicting or redundant options")));
            disreplication = defel;
        }
        else if (strcmp(defel->defname, "connectionlimit") == 0)
        {
            if (dconnlimit)
                ereport(ERROR,
                        (errcode(ERRCODE_SYNTAX_ERROR),
                         errmsg("conflicting or redundant options")));
            dconnlimit = defel;
        }
        else if (strcmp(defel->defname, "addroleto") == 0)
        {
            if (daddroleto)
                ereport(ERROR,
                        (errcode(ERRCODE_SYNTAX_ERROR),
                         errmsg("conflicting or redundant options")));
            daddroleto = defel;
        }
        else if (strcmp(defel->defname, "rolemembers") == 0)
        {
            if (drolemembers)
                ereport(ERROR,
                        (errcode(ERRCODE_SYNTAX_ERROR),
                         errmsg("conflicting or redundant options")));
            drolemembers = defel;
        }
        else if (strcmp(defel->defname, "adminmembers") == 0)
        {
            if (dadminmembers)
                ereport(ERROR,
                        (errcode(ERRCODE_SYNTAX_ERROR),
                         errmsg("conflicting or redundant options")));
            dadminmembers = defel;
        }
        else if (strcmp(defel->defname, "validUntil") == 0)
        {
            if (dvalidUntil)
                ereport(ERROR,
                        (errcode(ERRCODE_SYNTAX_ERROR),
                         errmsg("conflicting or redundant options")));
            dvalidUntil = defel;
        }
        else
            elog(ERROR, "option \"%s\" not recognized",
                 defel->defname);
    }

    if (dpassword && dpassword->arg)
        password = strVal(dpassword->arg);
    if (dissuper)
        issuper = intVal(dissuper->arg) != 0;
    if (dinherit)
        inherit = intVal(dinherit->arg) != 0;
    if (dcreaterole)
        createrole = intVal(dcreaterole->arg) != 0;
    if (dcreatedb)
        createdb = intVal(dcreatedb->arg) != 0;
    if (dcanlogin)
        canlogin = intVal(dcanlogin->arg) != 0;
    if (disreplication)
        isreplication = intVal(disreplication->arg) != 0;
    if (dconnlimit)
    {
        connlimit = intVal(dconnlimit->arg);
        if (connlimit < -1)
            ereport(ERROR,
                    (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
                     errmsg("invalid connection limit: %d", connlimit)));
    }
    if (daddroleto)
        addroleto = (List *) daddroleto->arg;
    if (drolemembers)
        rolemembers = (List *) drolemembers->arg;
    if (dadminmembers)
        adminmembers = (List *) dadminmembers->arg;
    if (dvalidUntil)
        validUntil = strVal(dvalidUntil->arg);

    /* Check some permissions first */
    if (issuper)
    {
        if (!superuser())
            ereport(ERROR,
                    (errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
                     errmsg("must be superuser to create superusers")));
    }
    else if (isreplication)
    {
        if (!superuser())
            ereport(ERROR,
                    (errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
                   errmsg("must be superuser to create replication users")));
    }
    else
    {
        if (!have_createrole_privilege())
            ereport(ERROR,
                    (errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
                     errmsg("permission denied to create role")));
    }

    if (strcmp(stmt->role, "public") == 0 ||
        strcmp(stmt->role, "none") == 0)
        ereport(ERROR,
                (errcode(ERRCODE_RESERVED_NAME),
                 errmsg("role name \"%s\" is reserved",
                        stmt->role)));

    /*
     * Check the pg_authid relation to be certain the role doesn't already
     * exist.
     */
    pg_authid_rel = heap_open(AuthIdRelationId, RowExclusiveLock);
    pg_authid_dsc = RelationGetDescr(pg_authid_rel);

    if (OidIsValid(get_role_oid(stmt->role, true)))
        ereport(ERROR,
                (errcode(ERRCODE_DUPLICATE_OBJECT),
                 errmsg("role \"%s\" already exists",
                        stmt->role)));

    /* Convert validuntil to internal form */
    if (validUntil)
    {
        validUntil_datum = DirectFunctionCall3(timestamptz_in,
                                               CStringGetDatum(validUntil),
                                               ObjectIdGetDatum(InvalidOid),
                                               Int32GetDatum(-1));
        validUntil_null = false;
    }
    else
    {
        validUntil_datum = (Datum) 0;
        validUntil_null = true;
    }

    /*
     * Call the password checking hook if there is one defined
     */
    if (check_password_hook && password)
        (*check_password_hook) (stmt->role,
                                password,
               isMD5(password) ? PASSWORD_TYPE_MD5 : PASSWORD_TYPE_PLAINTEXT,
                                validUntil_datum,
                                validUntil_null);

    /*
     * Build a tuple to insert
     */
    MemSet(new_record, 0, sizeof(new_record));
    MemSet(new_record_nulls, false, sizeof(new_record_nulls));

    new_record[Anum_pg_authid_rolname - 1] =
        DirectFunctionCall1(namein, CStringGetDatum(stmt->role));

    new_record[Anum_pg_authid_rolsuper - 1] = BoolGetDatum(issuper);
    new_record[Anum_pg_authid_rolinherit - 1] = BoolGetDatum(inherit);
    new_record[Anum_pg_authid_rolcreaterole - 1] = BoolGetDatum(createrole);
    new_record[Anum_pg_authid_rolcreatedb - 1] = BoolGetDatum(createdb);
    /* superuser gets catupdate right by default */
    new_record[Anum_pg_authid_rolcatupdate - 1] = BoolGetDatum(issuper);
    new_record[Anum_pg_authid_rolcanlogin - 1] = BoolGetDatum(canlogin);
    new_record[Anum_pg_authid_rolreplication - 1] = BoolGetDatum(isreplication);
    new_record[Anum_pg_authid_rolconnlimit - 1] = Int32GetDatum(connlimit);

    if (password)
    {
        if (!encrypt_password || isMD5(password))
            new_record[Anum_pg_authid_rolpassword - 1] =
                CStringGetTextDatum(password);
        else
        {
            if (!pg_md5_encrypt(password, stmt->role, strlen(stmt->role),
                                encrypted_password))
                elog(ERROR, "password encryption failed");
            new_record[Anum_pg_authid_rolpassword - 1] =
                CStringGetTextDatum(encrypted_password);
        }
    }
    else
        new_record_nulls[Anum_pg_authid_rolpassword - 1] = true;

    new_record[Anum_pg_authid_rolvaliduntil - 1] = validUntil_datum;
    new_record_nulls[Anum_pg_authid_rolvaliduntil - 1] = validUntil_null;

    tuple = heap_form_tuple(pg_authid_dsc, new_record, new_record_nulls);

    /*
     * pg_largeobject_metadata contains pg_authid.oid's, so we use the
     * binary-upgrade override, if specified.
     */
    if (IsBinaryUpgrade && OidIsValid(binary_upgrade_next_pg_authid_oid))
    {
        HeapTupleSetOid(tuple, binary_upgrade_next_pg_authid_oid);
        binary_upgrade_next_pg_authid_oid = InvalidOid;
    }

    /*
     * Insert new record in the pg_authid table
     */
    roleid = simple_heap_insert(pg_authid_rel, tuple);
    CatalogUpdateIndexes(pg_authid_rel, tuple);

    /*
     * Advance command counter so we can see new record; else tests in
     * AddRoleMems may fail.
     */
    if (addroleto || adminmembers || rolemembers)
        CommandCounterIncrement();

    /*
     * Add the new role to the specified existing roles.
     */
    foreach(item, addroleto)
    {
        char       *oldrolename = strVal(lfirst(item));
        Oid         oldroleid = get_role_oid(oldrolename, false);

        AddRoleMems(oldrolename, oldroleid,
                    list_make1(makeString(stmt->role)),
                    list_make1_oid(roleid),
                    GetUserId(), false);
    }

    /*
     * Add the specified members to this new role. adminmembers get the admin
     * option, rolemembers don't.
     */
    AddRoleMems(stmt->role, roleid,
                adminmembers, roleNamesToIds(adminmembers),
                GetUserId(), true);
    AddRoleMems(stmt->role, roleid,
                rolemembers, roleNamesToIds(rolemembers),
                GetUserId(), false);

    /* Post creation hook for new role */
    InvokeObjectPostCreateHook(AuthIdRelationId, roleid, 0);

    /*
     * Close pg_authid, but keep lock till commit.
     */
    heap_close(pg_authid_rel, NoLock);

    return roleid;
}

static void DelRoleMems ( const char *  rolename,
Oid  roleid,
List memberNames,
List memberIds,
bool  admin_opt 
) [static]

Definition at line 1470 of file user.c.

References Anum_pg_auth_members_admin_option, Assert, AuthMemRelationId, AUTHMEMROLEMEM, BoolGetDatum, CatalogUpdateIndexes(), CommandCounterIncrement(), ereport, errcode(), errmsg(), ERROR, forboth, GetUserId(), have_createrole_privilege(), heap_close, heap_modify_tuple(), heap_open(), HeapTupleIsValid, is_admin_of_role(), lfirst, lfirst_oid, list_length(), MemSet, NoLock, ObjectIdGetDatum, RelationGetDescr, ReleaseSysCache(), RowExclusiveLock, SearchSysCache2, simple_heap_delete(), simple_heap_update(), strVal, superuser(), superuser_arg(), HeapTupleData::t_self, and WARNING.

Referenced by AlterRole(), and GrantRole().

{
    Relation    pg_authmem_rel;
    TupleDesc   pg_authmem_dsc;
    ListCell   *nameitem;
    ListCell   *iditem;

    Assert(list_length(memberNames) == list_length(memberIds));

    /* Skip permission check if nothing to do */
    if (!memberIds)
        return;

    /*
     * Check permissions: must have createrole or admin option on the role to
     * be changed.  To mess with a superuser role, you gotta be superuser.
     */
    if (superuser_arg(roleid))
    {
        if (!superuser())
            ereport(ERROR,
                    (errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
                     errmsg("must be superuser to alter superusers")));
    }
    else
    {
        if (!have_createrole_privilege() &&
            !is_admin_of_role(GetUserId(), roleid))
            ereport(ERROR,
                    (errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
                     errmsg("must have admin option on role \"%s\"",
                            rolename)));
    }

    pg_authmem_rel = heap_open(AuthMemRelationId, RowExclusiveLock);
    pg_authmem_dsc = RelationGetDescr(pg_authmem_rel);

    forboth(nameitem, memberNames, iditem, memberIds)
    {
        const char *membername = strVal(lfirst(nameitem));
        Oid         memberid = lfirst_oid(iditem);
        HeapTuple   authmem_tuple;

        /*
         * Find entry for this role/member
         */
        authmem_tuple = SearchSysCache2(AUTHMEMROLEMEM,
                                        ObjectIdGetDatum(roleid),
                                        ObjectIdGetDatum(memberid));
        if (!HeapTupleIsValid(authmem_tuple))
        {
            ereport(WARNING,
                    (errmsg("role \"%s\" is not a member of role \"%s\"",
                            membername, rolename)));
            continue;
        }

        if (!admin_opt)
        {
            /* Remove the entry altogether */
            simple_heap_delete(pg_authmem_rel, &authmem_tuple->t_self);
        }
        else
        {
            /* Just turn off the admin option */
            HeapTuple   tuple;
            Datum       new_record[Natts_pg_auth_members];
            bool        new_record_nulls[Natts_pg_auth_members];
            bool        new_record_repl[Natts_pg_auth_members];

            /* Build a tuple to update with */
            MemSet(new_record, 0, sizeof(new_record));
            MemSet(new_record_nulls, false, sizeof(new_record_nulls));
            MemSet(new_record_repl, false, sizeof(new_record_repl));

            new_record[Anum_pg_auth_members_admin_option - 1] = BoolGetDatum(false);
            new_record_repl[Anum_pg_auth_members_admin_option - 1] = true;

            tuple = heap_modify_tuple(authmem_tuple, pg_authmem_dsc,
                                      new_record,
                                      new_record_nulls, new_record_repl);
            simple_heap_update(pg_authmem_rel, &tuple->t_self, tuple);
            CatalogUpdateIndexes(pg_authmem_rel, tuple);
        }

        ReleaseSysCache(authmem_tuple);

        /* CCI after each change, in case there are duplicates in list */
        CommandCounterIncrement();
    }

    /*
     * Close pg_authmem, but keep lock till commit.
     */
    heap_close(pg_authmem_rel, NoLock);
}

void DropOwnedObjects ( DropOwnedStmt stmt  ) 

Definition at line 1243 of file user.c.

References DropOwnedStmt::behavior, ereport, errcode(), errmsg(), ERROR, GetUserId(), has_privs_of_role(), lfirst_oid, roleNamesToIds(), DropOwnedStmt::roles, and shdepDropOwned().

Referenced by ProcessUtilitySlow().

{
    List       *role_ids = roleNamesToIds(stmt->roles);
    ListCell   *cell;

    /* Check privileges */
    foreach(cell, role_ids)
    {
        Oid         roleid = lfirst_oid(cell);

        if (!has_privs_of_role(GetUserId(), roleid))
            ereport(ERROR,
                    (errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
                     errmsg("permission denied to drop objects")));
    }

    /* Ok, do it */
    shdepDropOwned(role_ids, stmt->behavior);
}

void DropRole ( DropRoleStmt stmt  ) 

Definition at line 897 of file user.c.

References AccessExclusiveLock, Anum_pg_auth_members_member, Anum_pg_auth_members_roleid, AuthIdRelationId, AuthMemMemRoleIndexId, AuthMemRelationId, AuthMemRoleMemIndexId, AUTHNAME, BTEqualStrategyNumber, checkSharedDependencies(), CommandCounterIncrement(), DeleteSharedComments(), DeleteSharedSecurityLabel(), DropSetting(), ereport, errcode(), errdetail_internal(), errdetail_log(), errmsg(), ERROR, GetOuterUserId(), GetSessionUserId(), GETSTRUCT, GetUserId(), have_createrole_privilege(), heap_close, heap_open(), HeapTupleGetOid, HeapTupleIsValid, InvalidOid, InvokeObjectDropHook, lfirst, LockSharedObject(), DropRoleStmt::missing_ok, NoLock, NOTICE, ObjectIdGetDatum, PointerGetDatum, ReleaseSysCache(), DropRoleStmt::roles, RowExclusiveLock, ScanKeyInit(), SearchSysCache1, simple_heap_delete(), SnapshotNow, strVal, superuser(), systable_beginscan(), systable_endscan(), systable_getnext(), and HeapTupleData::t_self.

Referenced by standard_ProcessUtility().

{
    Relation    pg_authid_rel,
                pg_auth_members_rel;
    ListCell   *item;

    if (!have_createrole_privilege())
        ereport(ERROR,
                (errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
                 errmsg("permission denied to drop role")));

    /*
     * Scan the pg_authid relation to find the Oid of the role(s) to be
     * deleted.
     */
    pg_authid_rel = heap_open(AuthIdRelationId, RowExclusiveLock);
    pg_auth_members_rel = heap_open(AuthMemRelationId, RowExclusiveLock);

    foreach(item, stmt->roles)
    {
        const char *role = strVal(lfirst(item));
        HeapTuple   tuple,
                    tmp_tuple;
        ScanKeyData scankey;
        char       *detail;
        char       *detail_log;
        SysScanDesc sscan;
        Oid         roleid;

        tuple = SearchSysCache1(AUTHNAME, PointerGetDatum(role));
        if (!HeapTupleIsValid(tuple))
        {
            if (!stmt->missing_ok)
            {
                ereport(ERROR,
                        (errcode(ERRCODE_UNDEFINED_OBJECT),
                         errmsg("role \"%s\" does not exist", role)));
            }
            else
            {
                ereport(NOTICE,
                        (errmsg("role \"%s\" does not exist, skipping",
                                role)));
            }

            continue;
        }

        roleid = HeapTupleGetOid(tuple);

        if (roleid == GetUserId())
            ereport(ERROR,
                    (errcode(ERRCODE_OBJECT_IN_USE),
                     errmsg("current user cannot be dropped")));
        if (roleid == GetOuterUserId())
            ereport(ERROR,
                    (errcode(ERRCODE_OBJECT_IN_USE),
                     errmsg("current user cannot be dropped")));
        if (roleid == GetSessionUserId())
            ereport(ERROR,
                    (errcode(ERRCODE_OBJECT_IN_USE),
                     errmsg("session user cannot be dropped")));

        /*
         * For safety's sake, we allow createrole holders to drop ordinary
         * roles but not superuser roles.  This is mainly to avoid the
         * scenario where you accidentally drop the last superuser.
         */
        if (((Form_pg_authid) GETSTRUCT(tuple))->rolsuper &&
            !superuser())
            ereport(ERROR,
                    (errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
                     errmsg("must be superuser to drop superusers")));

        /* DROP hook for the role being removed */
        InvokeObjectDropHook(AuthIdRelationId, roleid, 0);

        /*
         * Lock the role, so nobody can add dependencies to her while we drop
         * her.  We keep the lock until the end of transaction.
         */
        LockSharedObject(AuthIdRelationId, roleid, 0, AccessExclusiveLock);

        /* Check for pg_shdepend entries depending on this role */
        if (checkSharedDependencies(AuthIdRelationId, roleid,
                                    &detail, &detail_log))
            ereport(ERROR,
                    (errcode(ERRCODE_DEPENDENT_OBJECTS_STILL_EXIST),
                     errmsg("role \"%s\" cannot be dropped because some objects depend on it",
                            role),
                     errdetail_internal("%s", detail),
                     errdetail_log("%s", detail_log)));

        /*
         * Remove the role from the pg_authid table
         */
        simple_heap_delete(pg_authid_rel, &tuple->t_self);

        ReleaseSysCache(tuple);

        /*
         * Remove role from the pg_auth_members table.  We have to remove all
         * tuples that show it as either a role or a member.
         *
         * XXX what about grantor entries?  Maybe we should do one heap scan.
         */
        ScanKeyInit(&scankey,
                    Anum_pg_auth_members_roleid,
                    BTEqualStrategyNumber, F_OIDEQ,
                    ObjectIdGetDatum(roleid));

        sscan = systable_beginscan(pg_auth_members_rel, AuthMemRoleMemIndexId,
                                   true, SnapshotNow, 1, &scankey);

        while (HeapTupleIsValid(tmp_tuple = systable_getnext(sscan)))
        {
            simple_heap_delete(pg_auth_members_rel, &tmp_tuple->t_self);
        }

        systable_endscan(sscan);

        ScanKeyInit(&scankey,
                    Anum_pg_auth_members_member,
                    BTEqualStrategyNumber, F_OIDEQ,
                    ObjectIdGetDatum(roleid));

        sscan = systable_beginscan(pg_auth_members_rel, AuthMemMemRoleIndexId,
                                   true, SnapshotNow, 1, &scankey);

        while (HeapTupleIsValid(tmp_tuple = systable_getnext(sscan)))
        {
            simple_heap_delete(pg_auth_members_rel, &tmp_tuple->t_self);
        }

        systable_endscan(sscan);

        /*
         * Remove any comments or security labels on this role.
         */
        DeleteSharedComments(roleid, AuthIdRelationId);
        DeleteSharedSecurityLabel(roleid, AuthIdRelationId);

        /*
         * Remove settings for this role.
         */
        DropSetting(InvalidOid, roleid);

        /*
         * Advance command counter so that later iterations of this loop will
         * see the changes already made.  This is essential if, for example,
         * we are trying to drop both a role and one of its direct members ---
         * we'll get an error if we try to delete the linking pg_auth_members
         * tuple twice.  (We do not need a CCI between the two delete loops
         * above, because it's not allowed for a role to directly contain
         * itself.)
         */
        CommandCounterIncrement();
    }

    /*
     * Now we can clean up; but keep locks until commit.
     */
    heap_close(pg_auth_members_rel, NoLock);
    heap_close(pg_authid_rel, NoLock);
}

void GrantRole ( GrantRoleStmt stmt  ) 

Definition at line 1184 of file user.c.

References AccessShareLock, AddRoleMems(), GrantRoleStmt::admin_opt, AuthIdRelationId, AccessPriv::cols, DelRoleMems(), ereport, errcode(), errmsg(), ERROR, get_role_oid(), GetUserId(), GrantRoleStmt::granted_roles, GrantRoleStmt::grantee_roles, GrantRoleStmt::grantor, heap_close, heap_open(), GrantRoleStmt::is_grant, lfirst, NIL, NoLock, NULL, AccessPriv::priv_name, and roleNamesToIds().

Referenced by standard_ProcessUtility().

{
    Relation    pg_authid_rel;
    Oid         grantor;
    List       *grantee_ids;
    ListCell   *item;

    if (stmt->grantor)
        grantor = get_role_oid(stmt->grantor, false);
    else
        grantor = GetUserId();

    grantee_ids = roleNamesToIds(stmt->grantee_roles);

    /* AccessShareLock is enough since we aren't modifying pg_authid */
    pg_authid_rel = heap_open(AuthIdRelationId, AccessShareLock);

    /*
     * Step through all of the granted roles and add/remove entries for the
     * grantees, or, if admin_opt is set, then just add/remove the admin
     * option.
     *
     * Note: Permissions checking is done by AddRoleMems/DelRoleMems
     */
    foreach(item, stmt->granted_roles)
    {
        AccessPriv *priv = (AccessPriv *) lfirst(item);
        char       *rolename = priv->priv_name;
        Oid         roleid;

        /* Must reject priv(columns) and ALL PRIVILEGES(columns) */
        if (rolename == NULL || priv->cols != NIL)
            ereport(ERROR,
                    (errcode(ERRCODE_INVALID_GRANT_OPERATION),
            errmsg("column names cannot be included in GRANT/REVOKE ROLE")));

        roleid = get_role_oid(rolename, false);
        if (stmt->is_grant)
            AddRoleMems(rolename, roleid,
                        stmt->grantee_roles, grantee_ids,
                        grantor, stmt->admin_opt);
        else
            DelRoleMems(rolename, roleid,
                        stmt->grantee_roles, grantee_ids,
                        stmt->admin_opt);
    }

    /*
     * Close pg_authid, but keep lock till commit.
     */
    heap_close(pg_authid_rel, NoLock);
}

static bool have_createrole_privilege ( void   )  [static]
void ReassignOwnedObjects ( ReassignOwnedStmt stmt  ) 

Definition at line 1269 of file user.c.

References ereport, errcode(), errmsg(), ERROR, get_role_oid(), GetUserId(), has_privs_of_role(), lfirst_oid, ReassignOwnedStmt::newrole, roleNamesToIds(), ReassignOwnedStmt::roles, and shdepReassignOwned().

Referenced by standard_ProcessUtility().

{
    List       *role_ids = roleNamesToIds(stmt->roles);
    ListCell   *cell;
    Oid         newrole;

    /* Check privileges */
    foreach(cell, role_ids)
    {
        Oid         roleid = lfirst_oid(cell);

        if (!has_privs_of_role(GetUserId(), roleid))
            ereport(ERROR,
                    (errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
                     errmsg("permission denied to reassign objects")));
    }

    /* Must have privileges on the receiving side too */
    newrole = get_role_oid(stmt->newrole, false);

    if (!has_privs_of_role(GetUserId(), newrole))
        ereport(ERROR,
                (errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
                 errmsg("permission denied to reassign objects")));

    /* Ok, do it */
    shdepReassignOwned(role_ids, newrole);
}

Oid RenameRole ( const char *  oldname,
const char *  newname 
)

Definition at line 1067 of file user.c.

References Anum_pg_authid_rolname, Anum_pg_authid_rolpassword, AuthIdRelationId, AUTHNAME, CatalogUpdateIndexes(), CStringGetDatum, DirectFunctionCall1, ereport, errcode(), errmsg(), ERROR, GetOuterUserId(), GetSessionUserId(), GETSTRUCT, have_createrole_privilege(), heap_close, heap_getattr, heap_modify_tuple(), heap_open(), HeapTupleGetOid, HeapTupleIsValid, i, InvokeObjectPostAlterHook, isMD5, namein(), NoLock, NOTICE, RelationGetDescr, ReleaseSysCache(), RowExclusiveLock, SearchSysCache1, SearchSysCacheExists1, simple_heap_update(), superuser(), HeapTupleData::t_self, and TextDatumGetCString.

Referenced by ExecRenameStmt().

{
    HeapTuple   oldtuple,
                newtuple;
    TupleDesc   dsc;
    Relation    rel;
    Datum       datum;
    bool        isnull;
    Datum       repl_val[Natts_pg_authid];
    bool        repl_null[Natts_pg_authid];
    bool        repl_repl[Natts_pg_authid];
    int         i;
    Oid         roleid;

    rel = heap_open(AuthIdRelationId, RowExclusiveLock);
    dsc = RelationGetDescr(rel);

    oldtuple = SearchSysCache1(AUTHNAME, CStringGetDatum(oldname));
    if (!HeapTupleIsValid(oldtuple))
        ereport(ERROR,
                (errcode(ERRCODE_UNDEFINED_OBJECT),
                 errmsg("role \"%s\" does not exist", oldname)));

    /*
     * XXX Client applications probably store the session user somewhere, so
     * renaming it could cause confusion.  On the other hand, there may not be
     * an actual problem besides a little confusion, so think about this and
     * decide.  Same for SET ROLE ... we don't restrict renaming the current
     * effective userid, though.
     */

    roleid = HeapTupleGetOid(oldtuple);

    if (roleid == GetSessionUserId())
        ereport(ERROR,
                (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
                 errmsg("session user cannot be renamed")));
    if (roleid == GetOuterUserId())
        ereport(ERROR,
                (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
                 errmsg("current user cannot be renamed")));

    /* make sure the new name doesn't exist */
    if (SearchSysCacheExists1(AUTHNAME, CStringGetDatum(newname)))
        ereport(ERROR,
                (errcode(ERRCODE_DUPLICATE_OBJECT),
                 errmsg("role \"%s\" already exists", newname)));

    if (strcmp(newname, "public") == 0 ||
        strcmp(newname, "none") == 0)
        ereport(ERROR,
                (errcode(ERRCODE_RESERVED_NAME),
                 errmsg("role name \"%s\" is reserved",
                        newname)));

    /*
     * createrole is enough privilege unless you want to mess with a superuser
     */
    if (((Form_pg_authid) GETSTRUCT(oldtuple))->rolsuper)
    {
        if (!superuser())
            ereport(ERROR,
                    (errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
                     errmsg("must be superuser to rename superusers")));
    }
    else
    {
        if (!have_createrole_privilege())
            ereport(ERROR,
                    (errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
                     errmsg("permission denied to rename role")));
    }

    /* OK, construct the modified tuple */
    for (i = 0; i < Natts_pg_authid; i++)
        repl_repl[i] = false;

    repl_repl[Anum_pg_authid_rolname - 1] = true;
    repl_val[Anum_pg_authid_rolname - 1] = DirectFunctionCall1(namein,
                                                   CStringGetDatum(newname));
    repl_null[Anum_pg_authid_rolname - 1] = false;

    datum = heap_getattr(oldtuple, Anum_pg_authid_rolpassword, dsc, &isnull);

    if (!isnull && isMD5(TextDatumGetCString(datum)))
    {
        /* MD5 uses the username as salt, so just clear it on a rename */
        repl_repl[Anum_pg_authid_rolpassword - 1] = true;
        repl_null[Anum_pg_authid_rolpassword - 1] = true;

        ereport(NOTICE,
                (errmsg("MD5 password cleared because of role rename")));
    }

    newtuple = heap_modify_tuple(oldtuple, dsc, repl_val, repl_null, repl_repl);
    simple_heap_update(rel, &oldtuple->t_self, newtuple);

    CatalogUpdateIndexes(rel, newtuple);

    InvokeObjectPostAlterHook(AuthIdRelationId, roleid, 0);

    ReleaseSysCache(oldtuple);

    /*
     * Close pg_authid, but keep lock till commit.
     */
    heap_close(rel, NoLock);

    return roleid;
}

static List * roleNamesToIds ( List memberNames  )  [static]

Definition at line 1305 of file user.c.

References get_role_oid(), lappend_oid(), lfirst, and strVal.

Referenced by AlterRole(), CreateRole(), DropOwnedObjects(), GrantRole(), and ReassignOwnedObjects().

{
    List       *result = NIL;
    ListCell   *l;

    foreach(l, memberNames)
    {
        char       *rolename = strVal(lfirst(l));
        Oid         roleid = get_role_oid(rolename, false);

        result = lappend_oid(result, roleid);
    }
    return result;
}


Variable Documentation

Definition at line 41 of file user.c.

Referenced by CreateRole(), and set_next_pg_authid_oid().

Definition at line 48 of file user.c.

Referenced by _PG_init(), AlterRole(), and CreateRole().

Definition at line 413 of file guc.c.

Referenced by AlterRole(), and CreateRole().