📄 user.c
字号:
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, "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) 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 (dconnlimit) connlimit = intVal(dconnlimit->arg); if (drolemembers) rolemembers = (List *) drolemembers->arg; if (dvalidUntil) validUntil = strVal(dvalidUntil->arg); /* * Scan the pg_authid relation to be certain the user exists. Note we * secure exclusive lock to protect our update of the flat auth file. */ pg_authid_rel = heap_open(AuthIdRelationId, ExclusiveLock); pg_authid_dsc = RelationGetDescr(pg_authid_rel); tuple = SearchSysCache(AUTHNAME, PointerGetDatum(stmt->role), 0, 0, 0); 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 (!have_createrole_privilege()) { if (!(inherit < 0 && createrole < 0 && createdb < 0 && canlogin < 0 && !dconnlimit && !rolemembers && !validUntil && password && roleid == GetUserId())) ereport(ERROR, (errcode(ERRCODE_INSUFFICIENT_PRIVILEGE), errmsg("permission denied"))); } /* * Build an updated tuple, perusing the information just obtained */ MemSet(new_record, 0, sizeof(new_record)); MemSet(new_record_nulls, ' ', sizeof(new_record_nulls)); MemSet(new_record_repl, ' ', 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] = 'r'; new_record[Anum_pg_authid_rolcatupdate - 1] = BoolGetDatum(issuper > 0); new_record_repl[Anum_pg_authid_rolcatupdate - 1] = 'r'; } if (inherit >= 0) { new_record[Anum_pg_authid_rolinherit - 1] = BoolGetDatum(inherit > 0); new_record_repl[Anum_pg_authid_rolinherit - 1] = 'r'; } if (createrole >= 0) { new_record[Anum_pg_authid_rolcreaterole - 1] = BoolGetDatum(createrole > 0); new_record_repl[Anum_pg_authid_rolcreaterole - 1] = 'r'; } if (createdb >= 0) { new_record[Anum_pg_authid_rolcreatedb - 1] = BoolGetDatum(createdb > 0); new_record_repl[Anum_pg_authid_rolcreatedb - 1] = 'r'; } if (canlogin >= 0) { new_record[Anum_pg_authid_rolcanlogin - 1] = BoolGetDatum(canlogin > 0); new_record_repl[Anum_pg_authid_rolcanlogin - 1] = 'r'; } if (dconnlimit) { new_record[Anum_pg_authid_rolconnlimit - 1] = Int32GetDatum(connlimit); new_record_repl[Anum_pg_authid_rolconnlimit - 1] = 'r'; } /* password */ if (password) { if (!encrypt_password || isMD5(password)) new_record[Anum_pg_authid_rolpassword - 1] = DirectFunctionCall1(textin, CStringGetDatum(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] = DirectFunctionCall1(textin, CStringGetDatum(encrypted_password)); } new_record_repl[Anum_pg_authid_rolpassword - 1] = 'r'; } /* valid until */ if (validUntil) { new_record[Anum_pg_authid_rolvaliduntil - 1] = DirectFunctionCall3(timestamptz_in, CStringGetDatum(validUntil), ObjectIdGetDatum(InvalidOid), Int32GetDatum(-1)); new_record_repl[Anum_pg_authid_rolvaliduntil - 1] = 'r'; } new_tuple = heap_modifytuple(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); 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); /* * Now we can clean up; but keep lock until commit (to avoid possible * deadlock when commit code tries to acquire lock). */ heap_close(pg_authid_rel, NoLock); /* * Set flag to update flat auth file at commit. */ auth_file_update_needed();}/* * ALTER ROLE ... SET */voidAlterRoleSet(AlterRoleSetStmt *stmt){ char *valuestr; HeapTuple oldtuple, newtuple; Relation rel; Datum repl_val[Natts_pg_authid]; char repl_null[Natts_pg_authid]; char repl_repl[Natts_pg_authid]; int i; valuestr = flatten_set_variable_args(stmt->variable, stmt->value); /* * RowExclusiveLock is sufficient, because we don't need to update the * flat auth file. */ rel = heap_open(AuthIdRelationId, RowExclusiveLock); oldtuple = SearchSysCache(AUTHNAME, PointerGetDatum(stmt->role), 0, 0, 0); if (!HeapTupleIsValid(oldtuple)) ereport(ERROR, (errcode(ERRCODE_UNDEFINED_OBJECT), errmsg("role \"%s\" does not exist", stmt->role))); /* * 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(oldtuple))->rolsuper) { if (!superuser()) ereport(ERROR, (errcode(ERRCODE_INSUFFICIENT_PRIVILEGE), errmsg("must be superuser to alter superusers"))); } else { if (!have_createrole_privilege() && HeapTupleGetOid(oldtuple) != GetUserId()) ereport(ERROR, (errcode(ERRCODE_INSUFFICIENT_PRIVILEGE), errmsg("permission denied"))); } for (i = 0; i < Natts_pg_authid; i++) repl_repl[i] = ' '; repl_repl[Anum_pg_authid_rolconfig - 1] = 'r'; if (strcmp(stmt->variable, "all") == 0 && valuestr == NULL) { /* RESET ALL */ repl_null[Anum_pg_authid_rolconfig - 1] = 'n'; } else { Datum datum; bool isnull; ArrayType *array; repl_null[Anum_pg_authid_rolconfig - 1] = ' '; datum = SysCacheGetAttr(AUTHNAME, oldtuple, Anum_pg_authid_rolconfig, &isnull); array = isnull ? NULL : DatumGetArrayTypeP(datum); if (valuestr) array = GUCArrayAdd(array, stmt->variable, valuestr); else array = GUCArrayDelete(array, stmt->variable); if (array) repl_val[Anum_pg_authid_rolconfig - 1] = PointerGetDatum(array); else repl_null[Anum_pg_authid_rolconfig - 1] = 'n'; } newtuple = heap_modifytuple(oldtuple, RelationGetDescr(rel), repl_val, repl_null, repl_repl); simple_heap_update(rel, &oldtuple->t_self, newtuple); CatalogUpdateIndexes(rel, newtuple); ReleaseSysCache(oldtuple); heap_close(rel, RowExclusiveLock);}/* * DROP ROLE */voidDropRole(DropRoleStmt *stmt){ 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. Note we secure exclusive lock on pg_authid, because we need * to protect our update of the flat auth file. A regular writer's lock * on pg_auth_members is sufficient though. */ pg_authid_rel = heap_open(AuthIdRelationId, ExclusiveLock); 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; SysScanDesc sscan; Oid roleid; tuple = SearchSysCache(AUTHNAME, PointerGetDatum(role), 0, 0, 0); if (!HeapTupleIsValid(tuple)) ereport(ERROR, (errcode(ERRCODE_UNDEFINED_OBJECT), errmsg("role \"%s\" does not exist", role))); 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"))); /* * 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 ((detail = checkSharedDependencies(AuthIdRelationId, roleid)) != NULL) ereport(ERROR, (errcode(ERRCODE_DEPENDENT_OBJECTS_STILL_EXIST), errmsg("role \"%s\" cannot be dropped because some objects depend on it", role), errdetail("%s", detail))); /* * 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); /* * 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(); }
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -