📄 user.c
字号:
if (!HeapTupleIsValid(tup)) ereport(ERROR, (errcode(ERRCODE_UNDEFINED_OBJECT), errmsg("user \"%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. */ if (((Form_pg_shadow) GETSTRUCT(tup))->usesysid == GetSessionUserId()) ereport(ERROR, (errcode(ERRCODE_FEATURE_NOT_SUPPORTED), errmsg("session user may not be renamed"))); /* make sure the new name doesn't exist */ if (SearchSysCacheExists(SHADOWNAME, CStringGetDatum(newname), 0, 0, 0)) ereport(ERROR, (errcode(ERRCODE_DUPLICATE_OBJECT), errmsg("user \"%s\" already exists", newname))); /* must be superuser */ if (!superuser()) ereport(ERROR, (errcode(ERRCODE_INSUFFICIENT_PRIVILEGE), errmsg("must be superuser to rename users"))); /* rename */ namestrcpy(&(((Form_pg_shadow) GETSTRUCT(tup))->usename), newname); simple_heap_update(rel, &tup->t_self, tup); CatalogUpdateIndexes(rel, tup); heap_close(rel, NoLock); heap_freetuple(tup); user_file_update_needed = true;}/* * CheckPgUserAclNotNull * * check to see if there is an ACL on pg_shadow */static voidCheckPgUserAclNotNull(void){ HeapTuple htup; htup = SearchSysCache(RELOID, ObjectIdGetDatum(RelOid_pg_shadow), 0, 0, 0); if (!HeapTupleIsValid(htup)) /* should not happen, we hope */ elog(ERROR, "cache lookup failed for relation %u", RelOid_pg_shadow); if (heap_attisnull(htup, Anum_pg_class_relacl)) ereport(ERROR, (errcode(ERRCODE_INSUFFICIENT_PRIVILEGE), errmsg("before using passwords you must revoke privileges on %s", ShadowRelationName), errdetail("This restriction is to prevent unprivileged users from reading the passwords."), errhint("Try REVOKE ALL ON \"%s\" FROM PUBLIC.", ShadowRelationName))); ReleaseSysCache(htup);}/* * CREATE GROUP */voidCreateGroup(CreateGroupStmt *stmt){ Relation pg_group_rel; HeapScanDesc scan; HeapTuple tuple; TupleDesc pg_group_dsc; bool group_exists = false, sysid_exists = false, havesysid = false; int max_id; Datum new_record[Natts_pg_group]; char new_record_nulls[Natts_pg_group]; List *item, *option, *newlist = NIL; IdList *grolist; int sysid = 0; List *userElts = NIL; DefElem *dsysid = NULL; DefElem *duserElts = NULL; foreach(option, stmt->options) { DefElem *defel = (DefElem *) lfirst(option); if (strcmp(defel->defname, "sysid") == 0) { if (dsysid) ereport(ERROR, (errcode(ERRCODE_SYNTAX_ERROR), errmsg("conflicting or redundant options"))); dsysid = defel; } else if (strcmp(defel->defname, "userElts") == 0) { if (duserElts) ereport(ERROR, (errcode(ERRCODE_SYNTAX_ERROR), errmsg("conflicting or redundant options"))); duserElts = defel; } else elog(ERROR, "option \"%s\" not recognized", defel->defname); } if (dsysid) { sysid = intVal(dsysid->arg); if (sysid <= 0) ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), errmsg("group ID must be positive"))); havesysid = true; } if (duserElts) userElts = (List *) duserElts->arg; /* * Make sure the user can do this. */ if (!superuser()) ereport(ERROR, (errcode(ERRCODE_INSUFFICIENT_PRIVILEGE), errmsg("must be superuser to create groups"))); if (strcmp(stmt->name, "public") == 0) ereport(ERROR, (errcode(ERRCODE_RESERVED_NAME), errmsg("group name \"%s\" is reserved", stmt->name))); /* * Scan the pg_group relation to be certain the group or id doesn't * already exist. Note we secure exclusive lock, because we also need * to be sure of what the next grosysid should be, and we need to * protect our eventual update of the flat group file. */ pg_group_rel = heap_openr(GroupRelationName, ExclusiveLock); pg_group_dsc = RelationGetDescr(pg_group_rel); scan = heap_beginscan(pg_group_rel, SnapshotNow, 0, NULL); max_id = 99; /* start auto-assigned ids at 100 */ while (!group_exists && !sysid_exists && (tuple = heap_getnext(scan, ForwardScanDirection)) != NULL) { Form_pg_group group_form = (Form_pg_group) GETSTRUCT(tuple); int32 this_sysid; group_exists = (strcmp(NameStr(group_form->groname), stmt->name) == 0); this_sysid = group_form->grosysid; if (havesysid) /* customized id wanted */ sysid_exists = (this_sysid == sysid); else { /* pick 1 + max */ if (this_sysid > max_id) max_id = this_sysid; } } heap_endscan(scan); if (group_exists) ereport(ERROR, (errcode(ERRCODE_DUPLICATE_OBJECT), errmsg("group \"%s\" already exists", stmt->name))); if (sysid_exists) ereport(ERROR, (errcode(ERRCODE_DUPLICATE_OBJECT), errmsg("group ID %d is already assigned", sysid))); /* If no sysid given, use max existing id + 1 */ if (!havesysid) sysid = max_id + 1; /* * Translate the given user names to ids */ foreach(item, userElts) { const char *groupuser = strVal(lfirst(item)); int32 userid = get_usesysid(groupuser); if (!intMember(userid, newlist)) newlist = lappendi(newlist, userid); } /* build an array to insert */ if (newlist) grolist = IdListToArray(newlist); else grolist = NULL; /* * Form a tuple to insert */ new_record[Anum_pg_group_groname - 1] = DirectFunctionCall1(namein, CStringGetDatum(stmt->name)); new_record[Anum_pg_group_grosysid - 1] = Int32GetDatum(sysid); new_record[Anum_pg_group_grolist - 1] = PointerGetDatum(grolist); new_record_nulls[Anum_pg_group_groname - 1] = ' '; new_record_nulls[Anum_pg_group_grosysid - 1] = ' '; new_record_nulls[Anum_pg_group_grolist - 1] = grolist ? ' ' : 'n'; tuple = heap_formtuple(pg_group_dsc, new_record, new_record_nulls); /* * Insert a new record in the pg_group table */ simple_heap_insert(pg_group_rel, tuple); /* Update indexes */ CatalogUpdateIndexes(pg_group_rel, tuple); /* * Now we can clean up; but keep lock until commit (to avoid possible * deadlock when commit code tries to acquire lock). */ heap_close(pg_group_rel, NoLock); /* * Set flag to update flat group file at commit. */ group_file_update_needed = true;}/* * ALTER GROUP */voidAlterGroup(AlterGroupStmt *stmt, const char *tag){ Relation pg_group_rel; TupleDesc pg_group_dsc; HeapTuple group_tuple; IdList *oldarray; Datum datum; bool null; List *newlist, *item; /* * Make sure the user can do this. */ if (!superuser()) ereport(ERROR, (errcode(ERRCODE_INSUFFICIENT_PRIVILEGE), errmsg("must be superuser to alter groups"))); /* * Secure exclusive lock to protect our update of the flat group file. */ pg_group_rel = heap_openr(GroupRelationName, ExclusiveLock); pg_group_dsc = RelationGetDescr(pg_group_rel); /* * Fetch existing tuple for group. */ group_tuple = SearchSysCache(GRONAME, PointerGetDatum(stmt->name), 0, 0, 0); if (!HeapTupleIsValid(group_tuple)) ereport(ERROR, (errcode(ERRCODE_UNDEFINED_OBJECT), errmsg("group \"%s\" does not exist", stmt->name))); /* Fetch old group membership. */ datum = heap_getattr(group_tuple, Anum_pg_group_grolist, pg_group_dsc, &null); oldarray = null ? ((IdList *) NULL) : DatumGetIdListP(datum); /* initialize list with old array contents */ newlist = IdArrayToList(oldarray); /* * Now decide what to do. */ AssertState(stmt->action == +1 || stmt->action == -1); if (stmt->action == +1) /* add users, might also be invoked by * create user */ { /* * convert the to be added usernames to sysids and add them to the * list */ foreach(item, stmt->listUsers) { int32 sysid; if (strcmp(tag, "ALTER GROUP") == 0) { /* Get the uid of the proposed user to add. */ sysid = get_usesysid(strVal(lfirst(item))); } else if (strcmp(tag, "CREATE USER") == 0) { /* * in this case we already know the uid and it wouldn't be * in the cache anyway yet */ sysid = intVal(lfirst(item)); } else { elog(ERROR, "unexpected tag: \"%s\"", tag); sysid = 0; /* keep compiler quiet */ } if (!intMember(sysid, newlist)) newlist = lappendi(newlist, sysid); } /* Do the update */ UpdateGroupMembership(pg_group_rel, group_tuple, newlist); } /* endif alter group add user */ else if (stmt->action == -1) /* drop users from group */ { bool is_dropuser = strcmp(tag, "DROP USER") == 0; if (newlist == NIL) { if (!is_dropuser) ereport(WARNING, (errcode(ERRCODE_WARNING), errmsg("group \"%s\" does not have any members", stmt->name))); } else { /* * convert the to be dropped usernames to sysids and remove * them from the list */ foreach(item, stmt->listUsers) { int32 sysid; if (!is_dropuser) { /* Get the uid of the proposed user to drop. */ sysid = get_usesysid(strVal(lfirst(item))); } else { /* for dropuser we already know the uid */ sysid = intVal(lfirst(item)); } if (intMember(sysid, newlist)) newlist = lremovei(sysid, newlist); else if (!is_dropuser) ereport(WARNING, (errcode(ERRCODE_WARNING), errmsg("user \"%s\" is not in group \"%s\"", strVal(lfirst(item)), stmt->name))); } /* Do the update */ UpdateGroupMembership(pg_group_rel, group_tuple, newlist); } /* endif group not null */ } /* endif alter group drop user */ ReleaseSysCache(group_tuple); /* * Now we can clean up; but keep lock until commit (to avoid possible * deadlock when commit code tries to acquire lock). */ heap_close(pg_group_rel, NoLock); /* * Set flag to update flat group file at commit. */ group_file_update_needed = true;}/* * Subroutine for AlterGroup: given a pg_group tuple and a desired new * membership (expressed as an integer list), form and write an updated tuple. * The pg_group relation must be open and locked already. */static voidUpdateGroupMembership(Relation group_rel, HeapTuple group_tuple, List *members){ IdList *newarray; Datum new_record[Natts_pg_group]; char new_record_nulls[Natts_pg_group]; char new_record_repl[Natts_pg_group]; HeapTuple tuple; newarray = IdListToArray(members); /* * Form an updated tuple with the new array and write it back. */ MemSet(new_record, 0, sizeof(new_record)); MemSet(new_record_nulls, ' ', sizeof(new_record_nulls)); MemSet(new_record_repl, ' ', sizeof(new_record_repl)); new_record[Anum_pg_group_grolist - 1] = PointerGetDatum(newarray); new_record_repl[Anum_pg_group_grolist - 1] = 'r'; tuple = heap_modifytuple(group_tuple, group_rel, new_record, new_record_nulls, new_record_repl); simple_heap_update(group_rel, &group_tuple->t_self, tuple); /* Update indexes */ CatalogUpdateIndexes(group_rel, tuple);}/* * Convert an integer list of sysids to an array. */static IdList *IdListToArray(List *members){ int nmembers = length(members); IdList *newarray; List *item; int i; newarray = palloc(ARR_OVERHEAD(1) + nmembers * sizeof(int32)); newarray->size = ARR_OVERHEAD(1) + nmembers * sizeof(int32); newarray->flags = 0; newarray->elemtype = INT4OID; ARR_NDIM(newarray) = 1; /* one dimensional array */ ARR_LBOUND(newarray)[0] = 1; /* axis starts at one */ ARR_DIMS(newarray)[0] = nmembers; /* axis is this long */ i = 0; foreach(item, members) ((int *) ARR_DATA_PTR(newarray))[i++] = lfirsti(item); return newarray;}/* * Convert an array of sysids to an integer list. */static List *IdArrayToList(IdList *oldarray){ List *newlist = NIL; int hibound, i; if (oldarray == NULL) return NIL; Assert(ARR_NDIM(oldarray) == 1); Assert(ARR_ELEMTYPE(oldarray) == INT4OID); hibound = ARR_DIMS(oldarray)[0]; for (i = 0; i < hibound; i++) { int32 sysid; sysid = ((int32 *) ARR_DATA_PTR(oldarray))[i]; /* filter out any duplicates --- probably a waste of time */ if (!intMember(sysid, newlist)) newlist = lappendi(newlist, sysid); } return newlist;}/* * DROP GROUP */voidDropGroup(DropGroupStmt *stmt){ Relation pg_group_rel; HeapTuple tuple; /* * Make sure the user can do this. */ if (!superuser()) ereport(ERROR, (errcode(ERRCODE_INSUFFICIENT_PRIVILEGE), errmsg("must be superuser to drop groups"))); /* * Secure exclusive lock to protect our update of the flat group file. */ pg_group_rel = heap_openr(GroupRelationName, ExclusiveLock); /* Find and delete the group. */ tuple = SearchSysCacheCopy(GRONAME, PointerGetDatum(stmt->name), 0, 0, 0); if (!HeapTupleIsValid(tuple)) ereport(ERROR, (errcode(ERRCODE_UNDEFINED_OBJECT), errmsg("group \"%s\" does not exist", stmt->name))); simple_heap_delete(pg_group_rel, &tuple->t_self); /* * Now we can clean up; but keep lock until commit (to avoid possible * deadlock when commit code tries to acquire lock). */ heap_close(pg_group_rel, NoLock); /* * Set flag to update flat group file at commit. */ group_file_update_needed = true;}/* * Rename group */voidRenameGroup(const char *oldname, const char *newname){ HeapTuple tup; Relation rel; /* ExclusiveLock because we need to update the flat group file */ rel = heap_openr(GroupRelationName, ExclusiveLock); tup = SearchSysCacheCopy(GRONAME, CStringGetDatum(oldname), 0, 0, 0); if (!HeapTupleIsValid(tup)) ereport(ERROR, (errcode(ERRCODE_UNDEFINED_OBJECT), errmsg("group \"%s\" does not exist", oldname))); /* make sure the new name doesn't exist */ if (SearchSysCacheExists(GRONAME, CStringGetDatum(newname), 0, 0, 0)) ereport(ERROR, (errcode(ERRCODE_DUPLICATE_OBJECT), errmsg("group \"%s\" already exists", newname))); /* must be superuser */ if (!superuser()) ereport(ERROR, (errcode(ERRCODE_INSUFFICIENT_PRIVILEGE), errmsg("must be superuser to rename groups"))); /* rename */ namestrcpy(&(((Form_pg_group) GETSTRUCT(tup))->groname), newname); simple_heap_update(rel, &tup->t_self, tup); CatalogUpdateIndexes(rel, tup); heap_close(rel, NoLock); heap_freetuple(tup); group_file_update_needed = true;}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -