aclchk.c
来自「PostgreSQL7.4.6 for Linux」· C语言 代码 · 共 1,557 行 · 第 1/3 页
C
1,557 行
/* keep the catalog indexes up to date */ CatalogUpdateIndexes(relation, newtuple); pfree(new_acl); heap_close(relation, RowExclusiveLock); }}static voidExecuteGrantStmt_Language(GrantStmt *stmt){ AclMode privileges; List *i; if (lfirsti(stmt->privileges) == ACL_ALL_RIGHTS) privileges = ACL_ALL_RIGHTS_LANGUAGE; else { privileges = ACL_NO_RIGHTS; foreach(i, stmt->privileges) { AclMode priv = lfirsti(i); if (priv & ~((AclMode) ACL_ALL_RIGHTS_LANGUAGE)) ereport(ERROR, (errcode(ERRCODE_INVALID_GRANT_OPERATION), errmsg("invalid privilege type %s for language", privilege_to_string(priv)))); privileges |= priv; } } foreach(i, stmt->objects) { char *langname = strVal(lfirst(i)); Relation relation; HeapTuple tuple; Form_pg_language pg_language_tuple; Datum aclDatum; bool isNull; Acl *old_acl; Acl *new_acl; AclId grantorId; AclId ownerId; HeapTuple newtuple; Datum values[Natts_pg_language]; char nulls[Natts_pg_language]; char replaces[Natts_pg_language]; relation = heap_openr(LanguageRelationName, RowExclusiveLock); tuple = SearchSysCache(LANGNAME, PointerGetDatum(langname), 0, 0, 0); if (!HeapTupleIsValid(tuple)) ereport(ERROR, (errcode(ERRCODE_UNDEFINED_OBJECT), errmsg("language \"%s\" does not exist", langname))); pg_language_tuple = (Form_pg_language) GETSTRUCT(tuple); /* * Note: for now, languages are treated as owned by the bootstrap * user. We should add an owner column to pg_language instead. */ ownerId = BOOTSTRAP_USESYSID; grantorId = select_grantor(ownerId); if (stmt->is_grant && !superuser() /* XXX no ownercheck() available */ && pg_language_aclcheck(HeapTupleGetOid(tuple), GetUserId(), ACL_GRANT_OPTION_FOR(privileges)) != ACLCHECK_OK) aclcheck_error(ACLCHECK_NO_PRIV, ACL_KIND_LANGUAGE, NameStr(pg_language_tuple->lanname)); if (!pg_language_tuple->lanpltrusted) ereport(ERROR, (errcode(ERRCODE_WRONG_OBJECT_TYPE), errmsg("language \"%s\" is not trusted", langname))); /* * If there's no ACL, substitute the proper default. */ aclDatum = SysCacheGetAttr(LANGNAME, tuple, Anum_pg_language_lanacl, &isNull); if (isNull) old_acl = acldefault(ACL_OBJECT_LANGUAGE, ownerId); else /* get a detoasted copy of the ACL */ old_acl = DatumGetAclPCopy(aclDatum); new_acl = merge_acl_with_grant(old_acl, stmt->is_grant, stmt->grant_option, stmt->behavior, stmt->grantees, privileges, grantorId, ownerId); /* finished building new ACL value, now insert it */ MemSet(values, 0, sizeof(values)); MemSet(nulls, ' ', sizeof(nulls)); MemSet(replaces, ' ', sizeof(replaces)); replaces[Anum_pg_language_lanacl - 1] = 'r'; values[Anum_pg_language_lanacl - 1] = PointerGetDatum(new_acl); newtuple = heap_modifytuple(tuple, relation, values, nulls, replaces); ReleaseSysCache(tuple); simple_heap_update(relation, &newtuple->t_self, newtuple); /* keep the catalog indexes up to date */ CatalogUpdateIndexes(relation, newtuple); pfree(new_acl); heap_close(relation, RowExclusiveLock); }}static voidExecuteGrantStmt_Namespace(GrantStmt *stmt){ AclMode privileges; List *i; if (lfirsti(stmt->privileges) == ACL_ALL_RIGHTS) privileges = ACL_ALL_RIGHTS_NAMESPACE; else { privileges = ACL_NO_RIGHTS; foreach(i, stmt->privileges) { AclMode priv = lfirsti(i); if (priv & ~((AclMode) ACL_ALL_RIGHTS_NAMESPACE)) ereport(ERROR, (errcode(ERRCODE_INVALID_GRANT_OPERATION), errmsg("invalid privilege type %s for schema", privilege_to_string(priv)))); privileges |= priv; } } foreach(i, stmt->objects) { char *nspname = strVal(lfirst(i)); Relation relation; HeapTuple tuple; Form_pg_namespace pg_namespace_tuple; Datum aclDatum; bool isNull; Acl *old_acl; Acl *new_acl; AclId grantorId; AclId ownerId; HeapTuple newtuple; Datum values[Natts_pg_namespace]; char nulls[Natts_pg_namespace]; char replaces[Natts_pg_namespace]; relation = heap_openr(NamespaceRelationName, RowExclusiveLock); tuple = SearchSysCache(NAMESPACENAME, CStringGetDatum(nspname), 0, 0, 0); if (!HeapTupleIsValid(tuple)) ereport(ERROR, (errcode(ERRCODE_UNDEFINED_SCHEMA), errmsg("schema \"%s\" does not exist", nspname))); pg_namespace_tuple = (Form_pg_namespace) GETSTRUCT(tuple); ownerId = pg_namespace_tuple->nspowner; grantorId = select_grantor(ownerId); if (stmt->is_grant && !pg_namespace_ownercheck(HeapTupleGetOid(tuple), GetUserId()) && pg_namespace_aclcheck(HeapTupleGetOid(tuple), GetUserId(), ACL_GRANT_OPTION_FOR(privileges)) != ACLCHECK_OK) aclcheck_error(ACLCHECK_NO_PRIV, ACL_KIND_NAMESPACE, nspname); /* * If there's no ACL, substitute the proper default. */ aclDatum = SysCacheGetAttr(NAMESPACENAME, tuple, Anum_pg_namespace_nspacl, &isNull); if (isNull) old_acl = acldefault(ACL_OBJECT_NAMESPACE, ownerId); else /* get a detoasted copy of the ACL */ old_acl = DatumGetAclPCopy(aclDatum); new_acl = merge_acl_with_grant(old_acl, stmt->is_grant, stmt->grant_option, stmt->behavior, stmt->grantees, privileges, grantorId, ownerId); /* finished building new ACL value, now insert it */ MemSet(values, 0, sizeof(values)); MemSet(nulls, ' ', sizeof(nulls)); MemSet(replaces, ' ', sizeof(replaces)); replaces[Anum_pg_namespace_nspacl - 1] = 'r'; values[Anum_pg_namespace_nspacl - 1] = PointerGetDatum(new_acl); newtuple = heap_modifytuple(tuple, relation, values, nulls, replaces); ReleaseSysCache(tuple); simple_heap_update(relation, &newtuple->t_self, newtuple); /* keep the catalog indexes up to date */ CatalogUpdateIndexes(relation, newtuple); pfree(new_acl); heap_close(relation, RowExclusiveLock); }}static const char *privilege_to_string(AclMode privilege){ switch (privilege) { case ACL_INSERT: return "INSERT"; case ACL_SELECT: return "SELECT"; case ACL_UPDATE: return "UPDATE"; case ACL_DELETE: return "DELETE"; case ACL_RULE: return "RULE"; case ACL_REFERENCES: return "REFERENCES"; case ACL_TRIGGER: return "TRIGGER"; case ACL_EXECUTE: return "EXECUTE"; case ACL_USAGE: return "USAGE"; case ACL_CREATE: return "CREATE"; case ACL_CREATE_TEMP: return "TEMP"; default: elog(ERROR, "unrecognized privilege: %d", (int) privilege); } return NULL; /* appease compiler */}AclIdget_grosysid(char *groname){ HeapTuple tuple; AclId id = 0; tuple = SearchSysCache(GRONAME, PointerGetDatum(groname), 0, 0, 0); if (HeapTupleIsValid(tuple)) { id = ((Form_pg_group) GETSTRUCT(tuple))->grosysid; ReleaseSysCache(tuple); } else ereport(ERROR, (errcode(ERRCODE_UNDEFINED_OBJECT), errmsg("group \"%s\" does not exist", groname))); return id;}/* * Convert group ID to name, or return NULL if group can't be found */char *get_groname(AclId grosysid){ HeapTuple tuple; char *name = NULL; tuple = SearchSysCache(GROSYSID, ObjectIdGetDatum(grosysid), 0, 0, 0); if (HeapTupleIsValid(tuple)) { name = pstrdup(NameStr(((Form_pg_group) GETSTRUCT(tuple))->groname)); ReleaseSysCache(tuple); } return name;}/* * Is user a member of group? */static boolin_group(AclId uid, AclId gid){ bool result = false; HeapTuple tuple; Datum att; bool isNull; IdList *glist; AclId *aidp; int i, num; tuple = SearchSysCache(GROSYSID, ObjectIdGetDatum(gid), 0, 0, 0); if (HeapTupleIsValid(tuple)) { att = SysCacheGetAttr(GROSYSID, tuple, Anum_pg_group_grolist, &isNull); if (!isNull) { /* be sure the IdList is not toasted */ glist = DatumGetIdListP(att); /* scan it */ num = IDLIST_NUM(glist); aidp = IDLIST_DAT(glist); for (i = 0; i < num; ++i) { if (aidp[i] == uid) { result = true; break; } } /* if IdList was toasted, free detoasted copy */ if ((Pointer) glist != DatumGetPointer(att)) pfree(glist); } ReleaseSysCache(tuple); } else ereport(WARNING, (errcode(ERRCODE_UNDEFINED_OBJECT), errmsg("group with ID %u does not exist", gid))); return result;}/* * aclcheck * * Returns ACLCHECK_OK if the 'userid' has ACL entries in 'acl' to * satisfy any one of the requirements of 'mode'. Returns an * appropriate ACLCHECK_* error code otherwise. */static AclResultaclcheck(Acl *acl, AclId userid, AclMode mode){ AclItem *aidat; int i, num; /* * Null ACL should not happen, since caller should have inserted * appropriate default */ if (acl == NULL) { elog(ERROR, "null ACL"); return ACLCHECK_NO_PRIV; } num = ACL_NUM(acl); aidat = ACL_DAT(acl); /* * See if privilege is granted directly to user or to public */ for (i = 0; i < num; i++) if (ACLITEM_GET_IDTYPE(aidat[i]) == ACL_IDTYPE_WORLD || (ACLITEM_GET_IDTYPE(aidat[i]) == ACL_IDTYPE_UID && aidat[i].ai_grantee == userid)) { if (aidat[i].ai_privs & mode) return ACLCHECK_OK; } /* * See if he has the permission via any group (do this in a separate * pass to avoid expensive(?) lookups in pg_group) */ for (i = 0; i < num; i++) if (ACLITEM_GET_IDTYPE(aidat[i]) == ACL_IDTYPE_GID && aidat[i].ai_privs & mode && in_group(userid, aidat[i].ai_grantee)) return ACLCHECK_OK; /* If here, doesn't have the privilege. */ return ACLCHECK_NO_PRIV;}/* * Standardized reporting of aclcheck permissions failures. * * Note: we do not double-quote the %s's below, because many callers * supply strings that might be already quoted. */static const char *const no_priv_msg[MAX_ACL_KIND] ={ /* ACL_KIND_CLASS */ gettext_noop("permission denied for relation %s"), /* ACL_KIND_DATABASE */ gettext_noop("permission denied for database %s"), /* ACL_KIND_PROC */ gettext_noop("permission denied for function %s"), /* ACL_KIND_OPER */ gettext_noop("permission denied for operator %s"), /* ACL_KIND_TYPE */ gettext_noop("permission denied for type %s"), /* ACL_KIND_LANGUAGE */ gettext_noop("permission denied for language %s"), /* ACL_KIND_NAMESPACE */ gettext_noop("permission denied for schema %s"), /* ACL_KIND_OPCLASS */ gettext_noop("permission denied for operator class %s"), /* ACL_KIND_CONVERSION */ gettext_noop("permission denied for conversion %s")};static const char *const not_owner_msg[MAX_ACL_KIND] ={ /* ACL_KIND_CLASS */ gettext_noop("must be owner of relation %s"), /* ACL_KIND_DATABASE */ gettext_noop("must be owner of database %s"), /* ACL_KIND_PROC */ gettext_noop("must be owner of function %s"), /* ACL_KIND_OPER */ gettext_noop("must be owner of operator %s"), /* ACL_KIND_TYPE */ gettext_noop("must be owner of type %s"), /* ACL_KIND_LANGUAGE */ gettext_noop("must be owner of language %s"), /* ACL_KIND_NAMESPACE */ gettext_noop("must be owner of schema %s"), /* ACL_KIND_OPCLASS */ gettext_noop("must be owner of operator class %s"), /* ACL_KIND_CONVERSION */ gettext_noop("must be owner of conversion %s")};voidaclcheck_error(AclResult aclerr, AclObjectKind objectkind, const char *objectname){ switch (aclerr) { case ACLCHECK_OK: /* no error, so return to caller */ break; case ACLCHECK_NO_PRIV: ereport(ERROR, (errcode(ERRCODE_INSUFFICIENT_PRIVILEGE), errmsg(no_priv_msg[objectkind], objectname))); break; case ACLCHECK_NOT_OWNER: ereport(ERROR, (errcode(ERRCODE_INSUFFICIENT_PRIVILEGE), errmsg(not_owner_msg[objectkind], objectname))); break; default: elog(ERROR, "unrecognized AclResult: %d", (int) aclerr); break; }}/* * Exported routine for checking a user's access privileges to a table * * Note: we give lookup failure the full ereport treatment because the * has_table_privilege() family of functions allow users to pass * any random OID to this function. Likewise for the sibling functions * below. */AclResultpg_class_aclcheck(Oid table_oid, AclId userid, AclMode mode){ AclResult result; bool usesuper, usecatupd; HeapTuple tuple; Form_pg_class classForm; Datum aclDatum; bool isNull; Acl *acl; /* * Validate userid, find out if he is superuser, also get usecatupd */ tuple = SearchSysCache(SHADOWSYSID, ObjectIdGetDatum(userid), 0, 0, 0); if (!HeapTupleIsValid(tuple)) ereport(ERROR, (errcode(ERRCODE_UNDEFINED_OBJECT), errmsg("user with ID %u does not exist", userid))); usecatupd = ((Form_pg_shadow) GETSTRUCT(tuple))->usecatupd; ReleaseSysCache(tuple); usesuper = superuser_arg(userid); /*
⌨️ 快捷键说明
复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?