/*------------------------------------------------------------------------- * * acl.c * Basic access control list data structures manipulation routines. * * Portions Copyright (c) 1996-2003, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * * IDENTIFICATION * $Header: /cvsroot/pgsql/src/backend/utils/adt/acl.c,v 1.94 2003/08/04 02:40:04 momjian Exp $ * *------------------------------------------------------------------------- */ #include "postgres.h" #include #include "catalog/namespace.h" #include "catalog/pg_shadow.h" #include "catalog/pg_type.h" #include "commands/dbcommands.h" #include "miscadmin.h" #include "utils/acl.h" #include "utils/builtins.h" #include "utils/lsyscache.h" #include "utils/syscache.h" #define ACL_IDTYPE_GID_KEYWORD "group" #define ACL_IDTYPE_UID_KEYWORD "user" static const char *getid(const char *s, char *n); static void putid(char *p, const char *s); static Acl *allocacl(int n); static const char *aclparse(const char *s, AclItem *aip); static bool aclitem_match(const AclItem *a1, const AclItem *a2); static Acl *recursive_revoke(Acl *acl, AclId grantee, AclMode revoke_privs, DropBehavior behavior); static AclMode convert_priv_string(text *priv_type_text); static Oid convert_table_name(text *tablename); static AclMode convert_table_priv_string(text *priv_type_text); static Oid convert_database_name(text *databasename); static AclMode convert_database_priv_string(text *priv_type_text); static Oid convert_function_name(text *functionname); static AclMode convert_function_priv_string(text *priv_type_text); static Oid convert_language_name(text *languagename); static AclMode convert_language_priv_string(text *priv_type_text); static Oid convert_schema_name(text *schemaname); static AclMode convert_schema_priv_string(text *priv_type_text); /* * getid * Consumes the first alphanumeric string (identifier) found in string * 's', ignoring any leading white space. If it finds a double quote * it returns the word inside the quotes. * * RETURNS: * the string position in 's' that points to the next non-space character * in 's', after any quotes. Also: * - loads the identifier into 'name'. (If no identifier is found, 'name' * contains an empty string.) name must be NAMEDATALEN bytes. */ static const char * getid(const char *s, char *n) { int len = 0; bool in_quotes = false; Assert(s && n); while (isspace((unsigned char) *s)) s++; /* This test had better match what putid() does, below */ for (; *s != '\0' && (isalnum((unsigned char) *s) || *s == '_' || *s == '"' || in_quotes); s++) { if (*s == '"') in_quotes = !in_quotes; else { if (len >= NAMEDATALEN - 1) ereport(ERROR, (errcode(ERRCODE_NAME_TOO_LONG), errmsg("identifier too long"), errdetail("Identifier must be less than %d characters.", NAMEDATALEN))); n[len++] = *s; } } n[len] = '\0'; while (isspace((unsigned char) *s)) s++; return s; } /* * Write a user or group Name at *p, surrounding it with double quotes if * needed. There must be at least NAMEDATALEN+2 bytes available at *p. */ static void putid(char *p, const char *s) { const char *src; bool safe = true; for (src = s; *src; src++) { /* This test had better match what getid() does, above */ if (!isalnum((unsigned char) *src) && *src != '_') { safe = false; break; } } if (!safe) *p++ = '"'; for (src = s; *src; src++) *p++ = *src; if (!safe) *p++ = '"'; *p = '\0'; } /* * aclparse * Consumes and parses an ACL specification of the form: * [group|user] [A-Za-z0-9]*=[rwaR]* * from string 's', ignoring any leading white space or white space * between the optional id type keyword (group|user) and the actual * ACL specification. * * This routine is called by the parser as well as aclitemin(), hence * the added generality. * * RETURNS: * the string position in 's' immediately following the ACL * specification. Also: * - loads the structure pointed to by 'aip' with the appropriate * UID/GID, id type identifier and mode type values. */ static const char * aclparse(const char *s, AclItem *aip) { AclMode privs, goption, read; uint32 idtype; char name[NAMEDATALEN]; char name2[NAMEDATALEN]; Assert(s && aip); #ifdef ACLDEBUG elog(LOG, "aclparse: input = \"%s\"", s); #endif idtype = ACL_IDTYPE_UID; s = getid(s, name); if (*s != '=') { /* we just read a keyword, not a name */ if (strcmp(name, ACL_IDTYPE_GID_KEYWORD) == 0) idtype = ACL_IDTYPE_GID; else if (strcmp(name, ACL_IDTYPE_UID_KEYWORD) != 0) ereport(ERROR, (errcode(ERRCODE_INVALID_TEXT_REPRESENTATION), errmsg("unrecognized keyword: \"%s\"", name), errhint("ACL keyword must be \"group\" or \"user\"."))); s = getid(s, name); /* move s to the name beyond the keyword */ if (name[0] == '\0') ereport(ERROR, (errcode(ERRCODE_INVALID_TEXT_REPRESENTATION), errmsg("missing name"), errhint("A name must follow the [group|user] keyword."))); } if (name[0] == '\0') idtype = ACL_IDTYPE_WORLD; if (*s != '=') ereport(ERROR, (errcode(ERRCODE_INVALID_TEXT_REPRESENTATION), errmsg("missing \"=\" sign"))); privs = goption = ACL_NO_RIGHTS; for (++s, read = 0; isalpha((unsigned char) *s) || *s == '*'; s++) { switch (*s) { case '*': goption |= read; break; case ACL_INSERT_CHR: read = ACL_INSERT; break; case ACL_SELECT_CHR: read = ACL_SELECT; break; case ACL_UPDATE_CHR: read = ACL_UPDATE; break; case ACL_DELETE_CHR: read = ACL_DELETE; break; case ACL_RULE_CHR: read = ACL_RULE; break; case ACL_REFERENCES_CHR: read = ACL_REFERENCES; break; case ACL_TRIGGER_CHR: read = ACL_TRIGGER; break; case ACL_EXECUTE_CHR: read = ACL_EXECUTE; break; case ACL_USAGE_CHR: read = ACL_USAGE; break; case ACL_CREATE_CHR: read = ACL_CREATE; break; case ACL_CREATE_TEMP_CHR: read = ACL_CREATE_TEMP; break; default: ereport(ERROR, (errcode(ERRCODE_INVALID_TEXT_REPRESENTATION), errmsg("invalid mode character: must be one of \"%s\"", ACL_ALL_RIGHTS_STR))); } privs |= read; } switch (idtype) { case ACL_IDTYPE_UID: aip->ai_grantee = get_usesysid(name); break; case ACL_IDTYPE_GID: aip->ai_grantee = get_grosysid(name); break; case ACL_IDTYPE_WORLD: aip->ai_grantee = ACL_ID_WORLD; break; } /* * XXX Allow a degree of backward compatibility by defaulting the * grantor to the superuser. */ if (*s == '/') { s = getid(s + 1, name2); if (name2[0] == '\0') ereport(ERROR, (errcode(ERRCODE_INVALID_TEXT_REPRESENTATION), errmsg("a name must follow the \"/\" sign"))); aip->ai_grantor = get_usesysid(name2); } else { aip->ai_grantor = BOOTSTRAP_USESYSID; ereport(WARNING, (errcode(ERRCODE_INVALID_GRANTOR), errmsg("defaulting grantor to %u", BOOTSTRAP_USESYSID))); } ACLITEM_SET_PRIVS_IDTYPE(*aip, privs, goption, idtype); #ifdef ACLDEBUG elog(LOG, "aclparse: correctly read [%x %d %x]", idtype, aip->ai_grantee, privs); #endif return s; } /* * allocacl * Allocates storage for a new Acl with 'n' entries. * * RETURNS: * the new Acl */ static Acl * allocacl(int n) { Acl *new_acl; Size size; if (n < 0) elog(ERROR, "invalid size: %d", n); size = ACL_N_SIZE(n); new_acl = (Acl *) palloc0(size); new_acl->size = size; new_acl->ndim = 1; new_acl->flags = 0; new_acl->elemtype = ACLITEMOID; ARR_LBOUND(new_acl)[0] = 0; ARR_DIMS(new_acl)[0] = n; return new_acl; } /* * aclitemin * Allocates storage for, and fills in, a new AclItem given a string * 's' that contains an ACL specification. See aclparse for details. * * RETURNS: * the new AclItem */ Datum aclitemin(PG_FUNCTION_ARGS) { const char *s = PG_GETARG_CSTRING(0); AclItem *aip; aip = (AclItem *) palloc(sizeof(AclItem)); s = aclparse(s, aip); while (isspace((unsigned char) *s)) ++s; if (*s) ereport(ERROR, (errcode(ERRCODE_INVALID_TEXT_REPRESENTATION), errmsg("extra garbage at the end of the ACL specification"))); PG_RETURN_ACLITEM_P(aip); } /* * aclitemout * Allocates storage for, and fills in, a new null-delimited string * containing a formatted ACL specification. See aclparse for details. * * RETURNS: * the new string */ Datum aclitemout(PG_FUNCTION_ARGS) { AclItem *aip = PG_GETARG_ACLITEM_P(0); char *p; char *out; HeapTuple htup; unsigned i; char *tmpname; out = palloc(strlen("group =/") + 2 * N_ACL_RIGHTS + 2 * (NAMEDATALEN + 2) + 1); p = out; *p = '\0'; switch (ACLITEM_GET_IDTYPE(*aip)) { case ACL_IDTYPE_UID: htup = SearchSysCache(SHADOWSYSID, ObjectIdGetDatum(aip->ai_grantee), 0, 0, 0); if (HeapTupleIsValid(htup)) { putid(p, NameStr(((Form_pg_shadow) GETSTRUCT(htup))->usename)); ReleaseSysCache(htup); } else { /* Generate numeric UID if we don't find an entry */ sprintf(p, "%d", aip->ai_grantee); } break; case ACL_IDTYPE_GID: strcpy(p, "group "); p += strlen(p); tmpname = get_groname(aip->ai_grantee); if (tmpname != NULL) putid(p, tmpname); else { /* Generate numeric GID if we don't find an entry */ sprintf(p, "%d", aip->ai_grantee); } break; case ACL_IDTYPE_WORLD: break; default: elog(ERROR, "unrecognized idtype: %d", (int) ACLITEM_GET_IDTYPE(*aip)); break; } while (*p) ++p; *p++ = '='; for (i = 0; i < N_ACL_RIGHTS; ++i) { if (ACLITEM_GET_PRIVS(*aip) & (1 << i)) *p++ = ACL_ALL_RIGHTS_STR[i]; if (ACLITEM_GET_GOPTIONS(*aip) & (1 << i)) *p++ = '*'; } *p++ = '/'; *p = '\0'; htup = SearchSysCache(SHADOWSYSID, ObjectIdGetDatum(aip->ai_grantor), 0, 0, 0); if (HeapTupleIsValid(htup)) { putid(p, NameStr(((Form_pg_shadow) GETSTRUCT(htup))->usename)); ReleaseSysCache(htup); } else { /* Generate numeric UID if we don't find an entry */ sprintf(p, "%d", aip->ai_grantor); } while (*p) ++p; *p = '\0'; PG_RETURN_CSTRING(out); } /* * aclitem_match * Two AclItems are considered to match iff they have the same * grantee and grantor; the privileges are ignored. */ static bool aclitem_match(const AclItem *a1, const AclItem *a2) { return ACLITEM_GET_IDTYPE(*a1) == ACLITEM_GET_IDTYPE(*a2) && a1->ai_grantee == a2->ai_grantee && a1->ai_grantor == a2->ai_grantor; } /* * aclitem equality operator */ Datum aclitem_eq(PG_FUNCTION_ARGS) { AclItem *a1 = PG_GETARG_ACLITEM_P(0); AclItem *a2 = PG_GETARG_ACLITEM_P(1); bool result; result = a1->ai_privs == a2->ai_privs && a1->ai_grantee == a2->ai_grantee && a1->ai_grantor == a2->ai_grantor; PG_RETURN_BOOL(result); } /* * acldefault() --- create an ACL describing default access permissions * * Change this routine if you want to alter the default access policy for * newly-created objects (or any object with a NULL acl entry). */ Acl * acldefault(GrantObjectType objtype, AclId ownerid) { AclMode world_default; AclMode owner_default; Acl *acl; AclItem *aip; switch (objtype) { case ACL_OBJECT_RELATION: world_default = ACL_NO_RIGHTS; owner_default = ACL_ALL_RIGHTS_RELATION; break; case ACL_OBJECT_DATABASE: world_default = ACL_CREATE_TEMP; /* not NO_RIGHTS! */ owner_default = ACL_ALL_RIGHTS_DATABASE; break; case ACL_OBJECT_FUNCTION: /* Grant EXECUTE by default, for now */ world_default = ACL_EXECUTE; owner_default = ACL_ALL_RIGHTS_FUNCTION; break; case ACL_OBJECT_LANGUAGE: /* Grant USAGE by default, for now */ world_default = ACL_USAGE; owner_default = ACL_ALL_RIGHTS_LANGUAGE; break; case ACL_OBJECT_NAMESPACE: world_default = ACL_NO_RIGHTS; owner_default = ACL_ALL_RIGHTS_NAMESPACE; break; default: elog(ERROR, "unrecognized objtype: %d", (int) objtype); world_default = ACL_NO_RIGHTS; /* keep compiler quiet */ owner_default = ACL_NO_RIGHTS; break; } acl = allocacl((world_default != ACL_NO_RIGHTS ? 1 : 0) + (ownerid ? 1 : 0)); aip = ACL_DAT(acl); if (world_default != ACL_NO_RIGHTS) { aip[0].ai_grantee = ACL_ID_WORLD; aip[0].ai_grantor = ownerid; ACLITEM_SET_PRIVS_IDTYPE(aip[0], world_default, ACL_NO_RIGHTS, ACL_IDTYPE_WORLD); } if (ownerid) { int index = (world_default != ACL_NO_RIGHTS ? 1 : 0); aip[index].ai_grantee = ownerid; aip[index].ai_grantor = ownerid; /* owner gets default privileges with grant option */ ACLITEM_SET_PRIVS_IDTYPE(aip[index], owner_default, owner_default, ACL_IDTYPE_UID); } return acl; } /* * Add or replace an item in an ACL array. The result is a modified copy; * the input object is not changed. * * NB: caller is responsible for having detoasted the input ACL, if needed. */ Acl * aclinsert3(const Acl *old_acl, const AclItem *mod_aip, unsigned modechg, DropBehavior behavior) { Acl *new_acl = NULL; AclItem *old_aip, *new_aip = NULL; int dst, num; /* These checks for null input are probably dead code, but... */ if (!old_acl || ACL_NUM(old_acl) < 1) old_acl = allocacl(1); if (!mod_aip) { new_acl = allocacl(ACL_NUM(old_acl)); memcpy((char *) new_acl, (char *) old_acl, ACL_SIZE(old_acl)); return new_acl; } num = ACL_NUM(old_acl); old_aip = ACL_DAT(old_acl); /* * Search the ACL for an existing entry for this grantee and grantor. * If one exists, just modify the entry in-place (well, in the same * position, since we actually return a copy); otherwise, insert the * new entry at the end. */ for (dst = 0; dst < num; ++dst) { if (aclitem_match(mod_aip, old_aip + dst)) { /* found a match, so modify existing item */ new_acl = allocacl(num); new_aip = ACL_DAT(new_acl); memcpy(new_acl, old_acl, ACL_SIZE(old_acl)); break; } } if (dst == num) { /* need to append a new item */ new_acl = allocacl(num + 1); new_aip = ACL_DAT(new_acl); memcpy(new_aip, old_aip, num * sizeof(AclItem)); /* initialize the new entry with no permissions */ new_aip[dst].ai_grantee = mod_aip->ai_grantee; new_aip[dst].ai_grantor = mod_aip->ai_grantor; ACLITEM_SET_PRIVS_IDTYPE(new_aip[dst], ACL_NO_RIGHTS, ACL_NO_RIGHTS, ACLITEM_GET_IDTYPE(*mod_aip)); num++; /* set num to the size of new_acl */ } /* apply the permissions mod */ switch (modechg) { case ACL_MODECHG_ADD: ACLITEM_SET_PRIVS(new_aip[dst], ACLITEM_GET_PRIVS(new_aip[dst]) | ACLITEM_GET_PRIVS(*mod_aip)); ACLITEM_SET_GOPTIONS(new_aip[dst], ACLITEM_GET_GOPTIONS(new_aip[dst]) | ACLITEM_GET_GOPTIONS(*mod_aip)); break; case ACL_MODECHG_DEL: ACLITEM_SET_PRIVS(new_aip[dst], ACLITEM_GET_PRIVS(new_aip[dst]) & ~ACLITEM_GET_PRIVS(*mod_aip)); ACLITEM_SET_GOPTIONS(new_aip[dst], ACLITEM_GET_GOPTIONS(new_aip[dst]) & ~ACLITEM_GET_GOPTIONS(*mod_aip)); break; case ACL_MODECHG_EQL: ACLITEM_SET_PRIVS_IDTYPE(new_aip[dst], ACLITEM_GET_PRIVS(*mod_aip), ACLITEM_GET_GOPTIONS(*mod_aip), ACLITEM_GET_IDTYPE(new_aip[dst])); break; } /* * If the adjusted entry has no permissions, delete it from the list. */ if (ACLITEM_GET_PRIVS(new_aip[dst]) == ACL_NO_RIGHTS) { memmove(new_aip + dst, new_aip + dst + 1, (num - dst - 1) * sizeof(AclItem)); ARR_DIMS(new_acl)[0] = num - 1; ARR_SIZE(new_acl) -= sizeof(AclItem); } /* * Remove abandoned privileges (cascading revoke) */ if (modechg != ACL_MODECHG_ADD && ACLITEM_GET_IDTYPE(*mod_aip) == ACL_IDTYPE_UID && ACLITEM_GET_GOPTIONS(*mod_aip)) new_acl = recursive_revoke(new_acl, mod_aip->ai_grantee, ACLITEM_GET_GOPTIONS(*mod_aip), behavior); return new_acl; } /* * Ensure that no privilege is "abandoned". A privilege is abandoned * if the user that granted the privilege loses the grant option. (So * the chain through which it was granted is broken.) Either the * abandoned privileges are revoked as well, or an error message is * printed, depending on the drop behavior option. */ static Acl * recursive_revoke(Acl *acl, AclId grantee, AclMode revoke_privs, DropBehavior behavior) { int i; restart: for (i = 0; i < ACL_NUM(acl); i++) { AclItem *aip = ACL_DAT(acl); if (aip[i].ai_grantor == grantee && (ACLITEM_GET_PRIVS(aip[i]) & revoke_privs) != 0) { AclItem mod_acl; if (behavior == DROP_RESTRICT) ereport(ERROR, (errcode(ERRCODE_DEPENDENT_OBJECTS_STILL_EXIST), errmsg("dependent privileges exist"), errhint("Use CASCADE to revoke them too."))); mod_acl.ai_grantor = grantee; mod_acl.ai_grantee = aip[i].ai_grantee; ACLITEM_SET_PRIVS_IDTYPE(mod_acl, revoke_privs, revoke_privs, ACLITEM_GET_IDTYPE(aip[i])); acl = aclinsert3(acl, &mod_acl, ACL_MODECHG_DEL, behavior); goto restart; } } return acl; } /* * aclinsert (exported function) */ Datum aclinsert(PG_FUNCTION_ARGS) { Acl *old_acl = PG_GETARG_ACL_P(0); AclItem *mod_aip = PG_GETARG_ACLITEM_P(1); PG_RETURN_ACL_P(aclinsert3(old_acl, mod_aip, ACL_MODECHG_EQL, DROP_CASCADE)); } Datum aclremove(PG_FUNCTION_ARGS) { Acl *old_acl = PG_GETARG_ACL_P(0); AclItem *mod_aip = PG_GETARG_ACLITEM_P(1); Acl *new_acl; AclItem *old_aip, *new_aip; int dst, old_num, new_num; /* These checks for null input should be dead code, but... */ if (!old_acl || ACL_NUM(old_acl) < 1) old_acl = allocacl(1); if (!mod_aip) { new_acl = allocacl(ACL_NUM(old_acl)); memcpy((char *) new_acl, (char *) old_acl, ACL_SIZE(old_acl)); PG_RETURN_ACL_P(new_acl); } old_num = ACL_NUM(old_acl); old_aip = ACL_DAT(old_acl); /* Search for the matching entry */ for (dst = 0; dst < old_num && !aclitem_match(mod_aip, old_aip + dst); ++dst) /* continue */ ; if (dst >= old_num) { /* Not found, so return copy of source ACL */ new_acl = allocacl(old_num); memcpy((char *) new_acl, (char *) old_acl, ACL_SIZE(old_acl)); } else { new_num = old_num - 1; new_acl = allocacl(new_num); new_aip = ACL_DAT(new_acl); if (dst == 0) { /* start */ ereport(ERROR, (errcode(ERRCODE_FEATURE_NOT_SUPPORTED), errmsg("cannot remove the world ACL"))); } else if (dst == old_num - 1) { /* end */ memcpy((char *) new_aip, (char *) old_aip, new_num * sizeof(AclItem)); } else { /* middle */ memcpy((char *) new_aip, (char *) old_aip, dst * sizeof(AclItem)); memcpy((char *) (new_aip + dst), (char *) (old_aip + dst + 1), (new_num - dst) * sizeof(AclItem)); } } PG_RETURN_ACL_P(new_acl); } Datum aclcontains(PG_FUNCTION_ARGS) { Acl *acl = PG_GETARG_ACL_P(0); AclItem *aip = PG_GETARG_ACLITEM_P(1); AclItem *aidat; int i, num; num = ACL_NUM(acl); aidat = ACL_DAT(acl); for (i = 0; i < num; ++i) { if (aip->ai_grantee == aidat[i].ai_grantee && ACLITEM_GET_IDTYPE(*aip) == ACLITEM_GET_IDTYPE(aidat[i]) && aip->ai_grantor == aidat[i].ai_grantor && (ACLITEM_GET_PRIVS(*aip) & ACLITEM_GET_PRIVS(aidat[i])) == ACLITEM_GET_PRIVS(*aip) && (ACLITEM_GET_GOPTIONS(*aip) & ACLITEM_GET_GOPTIONS(aidat[i])) == ACLITEM_GET_GOPTIONS(*aip)) PG_RETURN_BOOL(true); } PG_RETURN_BOOL(false); } Datum makeaclitem(PG_FUNCTION_ARGS) { int32 u_grantee = PG_GETARG_INT32(0); int32 g_grantee = PG_GETARG_INT32(1); int32 grantor = PG_GETARG_INT32(2); text *privtext = PG_GETARG_TEXT_P(3); bool goption = PG_GETARG_BOOL(4); AclItem *aclitem; AclMode priv; priv = convert_priv_string(privtext); aclitem = (AclItem *) palloc(sizeof(*aclitem)); if (u_grantee == 0 && g_grantee == 0) { aclitem ->ai_grantee = 0; ACLITEM_SET_IDTYPE(*aclitem, ACL_IDTYPE_WORLD); } else if (u_grantee != 0 && g_grantee != 0) { ereport(ERROR, (errcode(ERRCODE_FEATURE_NOT_SUPPORTED), errmsg("cannot specify both user and group"))); } else if (u_grantee != 0) { aclitem ->ai_grantee = u_grantee; ACLITEM_SET_IDTYPE(*aclitem, ACL_IDTYPE_UID); } else if (g_grantee != 0) { aclitem ->ai_grantee = g_grantee; ACLITEM_SET_IDTYPE(*aclitem, ACL_IDTYPE_GID); } aclitem ->ai_grantor = grantor; ACLITEM_SET_PRIVS(*aclitem, priv); if (goption) ACLITEM_SET_GOPTIONS(*aclitem, priv); else ACLITEM_SET_GOPTIONS(*aclitem, ACL_NO_RIGHTS); PG_RETURN_ACLITEM_P(aclitem); } static AclMode convert_priv_string(text *priv_type_text) { char *priv_type; priv_type = DatumGetCString(DirectFunctionCall1(textout, PointerGetDatum(priv_type_text))); if (strcasecmp(priv_type, "SELECT") == 0) return ACL_SELECT; if (strcasecmp(priv_type, "INSERT") == 0) return ACL_INSERT; if (strcasecmp(priv_type, "UPDATE") == 0) return ACL_UPDATE; if (strcasecmp(priv_type, "DELETE") == 0) return ACL_DELETE; if (strcasecmp(priv_type, "RULE") == 0) return ACL_RULE; if (strcasecmp(priv_type, "REFERENCES") == 0) return ACL_REFERENCES; if (strcasecmp(priv_type, "TRIGGER") == 0) return ACL_TRIGGER; if (strcasecmp(priv_type, "EXECUTE") == 0) return ACL_EXECUTE; if (strcasecmp(priv_type, "USAGE") == 0) return ACL_USAGE; if (strcasecmp(priv_type, "CREATE") == 0) return ACL_CREATE; if (strcasecmp(priv_type, "TEMP") == 0) return ACL_CREATE_TEMP; if (strcasecmp(priv_type, "TEMPORARY") == 0) return ACL_CREATE_TEMP; ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), errmsg("unrecognized privilege type: \"%s\"", priv_type))); return ACL_NO_RIGHTS; /* keep compiler quiet */ } /* * has_table_privilege variants * These are all named "has_table_privilege" at the SQL level. * They take various combinations of relation name, relation OID, * user name, user sysid, or implicit user = current_user. * * The result is a boolean value: true if user has the indicated * privilege, false if not. */ /* * has_table_privilege_name_name * Check user privileges on a table given * name username, text tablename, and text priv name. */ Datum has_table_privilege_name_name(PG_FUNCTION_ARGS) { Name username = PG_GETARG_NAME(0); text *tablename = PG_GETARG_TEXT_P(1); text *priv_type_text = PG_GETARG_TEXT_P(2); int32 usesysid; Oid tableoid; AclMode mode; AclResult aclresult; usesysid = get_usesysid(NameStr(*username)); tableoid = convert_table_name(tablename); mode = convert_table_priv_string(priv_type_text); aclresult = pg_class_aclcheck(tableoid, usesysid, mode); PG_RETURN_BOOL(aclresult == ACLCHECK_OK); } /* * has_table_privilege_name * Check user privileges on a table given * text tablename and text priv name. * current_user is assumed */ Datum has_table_privilege_name(PG_FUNCTION_ARGS) { text *tablename = PG_GETARG_TEXT_P(0); text *priv_type_text = PG_GETARG_TEXT_P(1); AclId usesysid; Oid tableoid; AclMode mode; AclResult aclresult; usesysid = GetUserId(); tableoid = convert_table_name(tablename); mode = convert_table_priv_string(priv_type_text); aclresult = pg_class_aclcheck(tableoid, usesysid, mode); PG_RETURN_BOOL(aclresult == ACLCHECK_OK); } /* * has_table_privilege_name_id * Check user privileges on a table given * name usename, table oid, and text priv name. */ Datum has_table_privilege_name_id(PG_FUNCTION_ARGS) { Name username = PG_GETARG_NAME(0); Oid tableoid = PG_GETARG_OID(1); text *priv_type_text = PG_GETARG_TEXT_P(2); int32 usesysid; AclMode mode; AclResult aclresult; usesysid = get_usesysid(NameStr(*username)); mode = convert_table_priv_string(priv_type_text); aclresult = pg_class_aclcheck(tableoid, usesysid, mode); PG_RETURN_BOOL(aclresult == ACLCHECK_OK); } /* * has_table_privilege_id * Check user privileges on a table given * table oid, and text priv name. * current_user is assumed */ Datum has_table_privilege_id(PG_FUNCTION_ARGS) { Oid tableoid = PG_GETARG_OID(0); text *priv_type_text = PG_GETARG_TEXT_P(1); AclId usesysid; AclMode mode; AclResult aclresult; usesysid = GetUserId(); mode = convert_table_priv_string(priv_type_text); aclresult = pg_class_aclcheck(tableoid, usesysid, mode); PG_RETURN_BOOL(aclresult == ACLCHECK_OK); } /* * has_table_privilege_id_name * Check user privileges on a table given * usesysid, text tablename, and text priv name. */ Datum has_table_privilege_id_name(PG_FUNCTION_ARGS) { int32 usesysid = PG_GETARG_INT32(0); text *tablename = PG_GETARG_TEXT_P(1); text *priv_type_text = PG_GETARG_TEXT_P(2); Oid tableoid; AclMode mode; AclResult aclresult; tableoid = convert_table_name(tablename); mode = convert_table_priv_string(priv_type_text); aclresult = pg_class_aclcheck(tableoid, usesysid, mode); PG_RETURN_BOOL(aclresult == ACLCHECK_OK); } /* * has_table_privilege_id_id * Check user privileges on a table given * usesysid, table oid, and text priv name. */ Datum has_table_privilege_id_id(PG_FUNCTION_ARGS) { int32 usesysid = PG_GETARG_INT32(0); Oid tableoid = PG_GETARG_OID(1); text *priv_type_text = PG_GETARG_TEXT_P(2); AclMode mode; AclResult aclresult; mode = convert_table_priv_string(priv_type_text); aclresult = pg_class_aclcheck(tableoid, usesysid, mode); PG_RETURN_BOOL(aclresult == ACLCHECK_OK); } /* * Support routines for has_table_privilege family. */ /* * Given a table name expressed as a string, look it up and return Oid */ static Oid convert_table_name(text *tablename) { RangeVar *relrv; relrv = makeRangeVarFromNameList(textToQualifiedNameList(tablename, "has_table_privilege")); return RangeVarGetRelid(relrv, false); } /* * convert_table_priv_string * Convert text string to AclMode value. */ static AclMode convert_table_priv_string(text *priv_type_text) { char *priv_type; priv_type = DatumGetCString(DirectFunctionCall1(textout, PointerGetDatum(priv_type_text))); /* * Return mode from priv_type string */ if (strcasecmp(priv_type, "SELECT") == 0) return ACL_SELECT; if (strcasecmp(priv_type, "SELECT WITH GRANT OPTION") == 0) return ACL_GRANT_OPTION_FOR(ACL_SELECT); if (strcasecmp(priv_type, "INSERT") == 0) return ACL_INSERT; if (strcasecmp(priv_type, "INSERT WITH GRANT OPTION") == 0) return ACL_GRANT_OPTION_FOR(ACL_INSERT); if (strcasecmp(priv_type, "UPDATE") == 0) return ACL_UPDATE; if (strcasecmp(priv_type, "UPDATE WITH GRANT OPTION") == 0) return ACL_GRANT_OPTION_FOR(ACL_UPDATE); if (strcasecmp(priv_type, "DELETE") == 0) return ACL_DELETE; if (strcasecmp(priv_type, "DELETE WITH GRANT OPTION") == 0) return ACL_GRANT_OPTION_FOR(ACL_DELETE); if (strcasecmp(priv_type, "RULE") == 0) return ACL_RULE; if (strcasecmp(priv_type, "RULE WITH GRANT OPTION") == 0) return ACL_GRANT_OPTION_FOR(ACL_RULE); if (strcasecmp(priv_type, "REFERENCES") == 0) return ACL_REFERENCES; if (strcasecmp(priv_type, "REFERENCES WITH GRANT OPTION") == 0) return ACL_GRANT_OPTION_FOR(ACL_REFERENCES); if (strcasecmp(priv_type, "TRIGGER") == 0) return ACL_TRIGGER; if (strcasecmp(priv_type, "TRIGGER WITH GRANT OPTION") == 0) return ACL_GRANT_OPTION_FOR(ACL_TRIGGER); ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), errmsg("unrecognized privilege type: \"%s\"", priv_type))); return ACL_NO_RIGHTS; /* keep compiler quiet */ } /* * has_database_privilege variants * These are all named "has_database_privilege" at the SQL level. * They take various combinations of database name, database OID, * user name, user sysid, or implicit user = current_user. * * The result is a boolean value: true if user has the indicated * privilege, false if not. */ /* * has_database_privilege_name_name * Check user privileges on a database given * name username, text databasename, and text priv name. */ Datum has_database_privilege_name_name(PG_FUNCTION_ARGS) { Name username = PG_GETARG_NAME(0); text *databasename = PG_GETARG_TEXT_P(1); text *priv_type_text = PG_GETARG_TEXT_P(2); int32 usesysid; Oid databaseoid; AclMode mode; AclResult aclresult; usesysid = get_usesysid(NameStr(*username)); databaseoid = convert_database_name(databasename); mode = convert_database_priv_string(priv_type_text); aclresult = pg_database_aclcheck(databaseoid, usesysid, mode); PG_RETURN_BOOL(aclresult == ACLCHECK_OK); } /* * has_database_privilege_name * Check user privileges on a database given * text databasename and text priv name. * current_user is assumed */ Datum has_database_privilege_name(PG_FUNCTION_ARGS) { text *databasename = PG_GETARG_TEXT_P(0); text *priv_type_text = PG_GETARG_TEXT_P(1); AclId usesysid; Oid databaseoid; AclMode mode; AclResult aclresult; usesysid = GetUserId(); databaseoid = convert_database_name(databasename); mode = convert_database_priv_string(priv_type_text); aclresult = pg_database_aclcheck(databaseoid, usesysid, mode); PG_RETURN_BOOL(aclresult == ACLCHECK_OK); } /* * has_database_privilege_name_id * Check user privileges on a database given * name usename, database oid, and text priv name. */ Datum has_database_privilege_name_id(PG_FUNCTION_ARGS) { Name username = PG_GETARG_NAME(0); Oid databaseoid = PG_GETARG_OID(1); text *priv_type_text = PG_GETARG_TEXT_P(2); int32 usesysid; AclMode mode; AclResult aclresult; usesysid = get_usesysid(NameStr(*username)); mode = convert_database_priv_string(priv_type_text); aclresult = pg_database_aclcheck(databaseoid, usesysid, mode); PG_RETURN_BOOL(aclresult == ACLCHECK_OK); } /* * has_database_privilege_id * Check user privileges on a database given * database oid, and text priv name. * current_user is assumed */ Datum has_database_privilege_id(PG_FUNCTION_ARGS) { Oid databaseoid = PG_GETARG_OID(0); text *priv_type_text = PG_GETARG_TEXT_P(1); AclId usesysid; AclMode mode; AclResult aclresult; usesysid = GetUserId(); mode = convert_database_priv_string(priv_type_text); aclresult = pg_database_aclcheck(databaseoid, usesysid, mode); PG_RETURN_BOOL(aclresult == ACLCHECK_OK); } /* * has_database_privilege_id_name * Check user privileges on a database given * usesysid, text databasename, and text priv name. */ Datum has_database_privilege_id_name(PG_FUNCTION_ARGS) { int32 usesysid = PG_GETARG_INT32(0); text *databasename = PG_GETARG_TEXT_P(1); text *priv_type_text = PG_GETARG_TEXT_P(2); Oid databaseoid; AclMode mode; AclResult aclresult; databaseoid = convert_database_name(databasename); mode = convert_database_priv_string(priv_type_text); aclresult = pg_database_aclcheck(databaseoid, usesysid, mode); PG_RETURN_BOOL(aclresult == ACLCHECK_OK); } /* * has_database_privilege_id_id * Check user privileges on a database given * usesysid, database oid, and text priv name. */ Datum has_database_privilege_id_id(PG_FUNCTION_ARGS) { int32 usesysid = PG_GETARG_INT32(0); Oid databaseoid = PG_GETARG_OID(1); text *priv_type_text = PG_GETARG_TEXT_P(2); AclMode mode; AclResult aclresult; mode = convert_database_priv_string(priv_type_text); aclresult = pg_database_aclcheck(databaseoid, usesysid, mode); PG_RETURN_BOOL(aclresult == ACLCHECK_OK); } /* * Support routines for has_database_privilege family. */ /* * Given a database name expressed as a string, look it up and return Oid */ static Oid convert_database_name(text *databasename) { char *dbname; Oid oid; dbname = DatumGetCString(DirectFunctionCall1(textout, PointerGetDatum(databasename))); oid = get_database_oid(dbname); if (!OidIsValid(oid)) ereport(ERROR, (errcode(ERRCODE_UNDEFINED_DATABASE), errmsg("database \"%s\" does not exist", dbname))); return oid; } /* * convert_database_priv_string * Convert text string to AclMode value. */ static AclMode convert_database_priv_string(text *priv_type_text) { char *priv_type; priv_type = DatumGetCString(DirectFunctionCall1(textout, PointerGetDatum(priv_type_text))); /* * Return mode from priv_type string */ if (strcasecmp(priv_type, "CREATE") == 0) return ACL_CREATE; if (strcasecmp(priv_type, "CREATE WITH GRANT OPTION") == 0) return ACL_GRANT_OPTION_FOR(ACL_CREATE); if (strcasecmp(priv_type, "TEMPORARY") == 0) return ACL_CREATE_TEMP; if (strcasecmp(priv_type, "TEMPORARY WITH GRANT OPTION") == 0) return ACL_GRANT_OPTION_FOR(ACL_CREATE_TEMP); if (strcasecmp(priv_type, "TEMP") == 0) return ACL_CREATE_TEMP; if (strcasecmp(priv_type, "TEMP WITH GRANT OPTION") == 0) return ACL_GRANT_OPTION_FOR(ACL_CREATE_TEMP); ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), errmsg("unrecognized privilege type: \"%s\"", priv_type))); return ACL_NO_RIGHTS; /* keep compiler quiet */ } /* * has_function_privilege variants * These are all named "has_function_privilege" at the SQL level. * They take various combinations of function name, function OID, * user name, user sysid, or implicit user = current_user. * * The result is a boolean value: true if user has the indicated * privilege, false if not. */ /* * has_function_privilege_name_name * Check user privileges on a function given * name username, text functionname, and text priv name. */ Datum has_function_privilege_name_name(PG_FUNCTION_ARGS) { Name username = PG_GETARG_NAME(0); text *functionname = PG_GETARG_TEXT_P(1); text *priv_type_text = PG_GETARG_TEXT_P(2); int32 usesysid; Oid functionoid; AclMode mode; AclResult aclresult; usesysid = get_usesysid(NameStr(*username)); functionoid = convert_function_name(functionname); mode = convert_function_priv_string(priv_type_text); aclresult = pg_proc_aclcheck(functionoid, usesysid, mode); PG_RETURN_BOOL(aclresult == ACLCHECK_OK); } /* * has_function_privilege_name * Check user privileges on a function given * text functionname and text priv name. * current_user is assumed */ Datum has_function_privilege_name(PG_FUNCTION_ARGS) { text *functionname = PG_GETARG_TEXT_P(0); text *priv_type_text = PG_GETARG_TEXT_P(1); AclId usesysid; Oid functionoid; AclMode mode; AclResult aclresult; usesysid = GetUserId(); functionoid = convert_function_name(functionname); mode = convert_function_priv_string(priv_type_text); aclresult = pg_proc_aclcheck(functionoid, usesysid, mode); PG_RETURN_BOOL(aclresult == ACLCHECK_OK); } /* * has_function_privilege_name_id * Check user privileges on a function given * name usename, function oid, and text priv name. */ Datum has_function_privilege_name_id(PG_FUNCTION_ARGS) { Name username = PG_GETARG_NAME(0); Oid functionoid = PG_GETARG_OID(1); text *priv_type_text = PG_GETARG_TEXT_P(2); int32 usesysid; AclMode mode; AclResult aclresult; usesysid = get_usesysid(NameStr(*username)); mode = convert_function_priv_string(priv_type_text); aclresult = pg_proc_aclcheck(functionoid, usesysid, mode); PG_RETURN_BOOL(aclresult == ACLCHECK_OK); } /* * has_function_privilege_id * Check user privileges on a function given * function oid, and text priv name. * current_user is assumed */ Datum has_function_privilege_id(PG_FUNCTION_ARGS) { Oid functionoid = PG_GETARG_OID(0); text *priv_type_text = PG_GETARG_TEXT_P(1); AclId usesysid; AclMode mode; AclResult aclresult; usesysid = GetUserId(); mode = convert_function_priv_string(priv_type_text); aclresult = pg_proc_aclcheck(functionoid, usesysid, mode); PG_RETURN_BOOL(aclresult == ACLCHECK_OK); } /* * has_function_privilege_id_name * Check user privileges on a function given * usesysid, text functionname, and text priv name. */ Datum has_function_privilege_id_name(PG_FUNCTION_ARGS) { int32 usesysid = PG_GETARG_INT32(0); text *functionname = PG_GETARG_TEXT_P(1); text *priv_type_text = PG_GETARG_TEXT_P(2); Oid functionoid; AclMode mode; AclResult aclresult; functionoid = convert_function_name(functionname); mode = convert_function_priv_string(priv_type_text); aclresult = pg_proc_aclcheck(functionoid, usesysid, mode); PG_RETURN_BOOL(aclresult == ACLCHECK_OK); } /* * has_function_privilege_id_id * Check user privileges on a function given * usesysid, function oid, and text priv name. */ Datum has_function_privilege_id_id(PG_FUNCTION_ARGS) { int32 usesysid = PG_GETARG_INT32(0); Oid functionoid = PG_GETARG_OID(1); text *priv_type_text = PG_GETARG_TEXT_P(2); AclMode mode; AclResult aclresult; mode = convert_function_priv_string(priv_type_text); aclresult = pg_proc_aclcheck(functionoid, usesysid, mode); PG_RETURN_BOOL(aclresult == ACLCHECK_OK); } /* * Support routines for has_function_privilege family. */ /* * Given a function name expressed as a string, look it up and return Oid */ static Oid convert_function_name(text *functionname) { char *funcname; Oid oid; funcname = DatumGetCString(DirectFunctionCall1(textout, PointerGetDatum(functionname))); oid = DatumGetObjectId(DirectFunctionCall1(regprocedurein, CStringGetDatum(funcname))); if (!OidIsValid(oid)) ereport(ERROR, (errcode(ERRCODE_UNDEFINED_FUNCTION), errmsg("function \"%s\" does not exist", funcname))); return oid; } /* * convert_function_priv_string * Convert text string to AclMode value. */ static AclMode convert_function_priv_string(text *priv_type_text) { char *priv_type; priv_type = DatumGetCString(DirectFunctionCall1(textout, PointerGetDatum(priv_type_text))); /* * Return mode from priv_type string */ if (strcasecmp(priv_type, "EXECUTE") == 0) return ACL_EXECUTE; if (strcasecmp(priv_type, "EXECUTE WITH GRANT OPTION") == 0) return ACL_GRANT_OPTION_FOR(ACL_EXECUTE); ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), errmsg("unrecognized privilege type: \"%s\"", priv_type))); return ACL_NO_RIGHTS; /* keep compiler quiet */ } /* * has_language_privilege variants * These are all named "has_language_privilege" at the SQL level. * They take various combinations of language name, language OID, * user name, user sysid, or implicit user = current_user. * * The result is a boolean value: true if user has the indicated * privilege, false if not. */ /* * has_language_privilege_name_name * Check user privileges on a language given * name username, text languagename, and text priv name. */ Datum has_language_privilege_name_name(PG_FUNCTION_ARGS) { Name username = PG_GETARG_NAME(0); text *languagename = PG_GETARG_TEXT_P(1); text *priv_type_text = PG_GETARG_TEXT_P(2); int32 usesysid; Oid languageoid; AclMode mode; AclResult aclresult; usesysid = get_usesysid(NameStr(*username)); languageoid = convert_language_name(languagename); mode = convert_language_priv_string(priv_type_text); aclresult = pg_language_aclcheck(languageoid, usesysid, mode); PG_RETURN_BOOL(aclresult == ACLCHECK_OK); } /* * has_language_privilege_name * Check user privileges on a language given * text languagename and text priv name. * current_user is assumed */ Datum has_language_privilege_name(PG_FUNCTION_ARGS) { text *languagename = PG_GETARG_TEXT_P(0); text *priv_type_text = PG_GETARG_TEXT_P(1); AclId usesysid; Oid languageoid; AclMode mode; AclResult aclresult; usesysid = GetUserId(); languageoid = convert_language_name(languagename); mode = convert_language_priv_string(priv_type_text); aclresult = pg_language_aclcheck(languageoid, usesysid, mode); PG_RETURN_BOOL(aclresult == ACLCHECK_OK); } /* * has_language_privilege_name_id * Check user privileges on a language given * name usename, language oid, and text priv name. */ Datum has_language_privilege_name_id(PG_FUNCTION_ARGS) { Name username = PG_GETARG_NAME(0); Oid languageoid = PG_GETARG_OID(1); text *priv_type_text = PG_GETARG_TEXT_P(2); int32 usesysid; AclMode mode; AclResult aclresult; usesysid = get_usesysid(NameStr(*username)); mode = convert_language_priv_string(priv_type_text); aclresult = pg_language_aclcheck(languageoid, usesysid, mode); PG_RETURN_BOOL(aclresult == ACLCHECK_OK); } /* * has_language_privilege_id * Check user privileges on a language given * language oid, and text priv name. * current_user is assumed */ Datum has_language_privilege_id(PG_FUNCTION_ARGS) { Oid languageoid = PG_GETARG_OID(0); text *priv_type_text = PG_GETARG_TEXT_P(1); AclId usesysid; AclMode mode; AclResult aclresult; usesysid = GetUserId(); mode = convert_language_priv_string(priv_type_text); aclresult = pg_language_aclcheck(languageoid, usesysid, mode); PG_RETURN_BOOL(aclresult == ACLCHECK_OK); } /* * has_language_privilege_id_name * Check user privileges on a language given * usesysid, text languagename, and text priv name. */ Datum has_language_privilege_id_name(PG_FUNCTION_ARGS) { int32 usesysid = PG_GETARG_INT32(0); text *languagename = PG_GETARG_TEXT_P(1); text *priv_type_text = PG_GETARG_TEXT_P(2); Oid languageoid; AclMode mode; AclResult aclresult; languageoid = convert_language_name(languagename); mode = convert_language_priv_string(priv_type_text); aclresult = pg_language_aclcheck(languageoid, usesysid, mode); PG_RETURN_BOOL(aclresult == ACLCHECK_OK); } /* * has_language_privilege_id_id * Check user privileges on a language given * usesysid, language oid, and text priv name. */ Datum has_language_privilege_id_id(PG_FUNCTION_ARGS) { int32 usesysid = PG_GETARG_INT32(0); Oid languageoid = PG_GETARG_OID(1); text *priv_type_text = PG_GETARG_TEXT_P(2); AclMode mode; AclResult aclresult; mode = convert_language_priv_string(priv_type_text); aclresult = pg_language_aclcheck(languageoid, usesysid, mode); PG_RETURN_BOOL(aclresult == ACLCHECK_OK); } /* * Support routines for has_language_privilege family. */ /* * Given a language name expressed as a string, look it up and return Oid */ static Oid convert_language_name(text *languagename) { char *langname; Oid oid; langname = DatumGetCString(DirectFunctionCall1(textout, PointerGetDatum(languagename))); oid = GetSysCacheOid(LANGNAME, CStringGetDatum(langname), 0, 0, 0); if (!OidIsValid(oid)) ereport(ERROR, (errcode(ERRCODE_UNDEFINED_OBJECT), errmsg("language \"%s\" does not exist", langname))); return oid; } /* * convert_language_priv_string * Convert text string to AclMode value. */ static AclMode convert_language_priv_string(text *priv_type_text) { char *priv_type; priv_type = DatumGetCString(DirectFunctionCall1(textout, PointerGetDatum(priv_type_text))); /* * Return mode from priv_type string */ if (strcasecmp(priv_type, "USAGE") == 0) return ACL_USAGE; if (strcasecmp(priv_type, "USAGE WITH GRANT OPTION") == 0) return ACL_GRANT_OPTION_FOR(ACL_USAGE); ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), errmsg("unrecognized privilege type: \"%s\"", priv_type))); return ACL_NO_RIGHTS; /* keep compiler quiet */ } /* * has_schema_privilege variants * These are all named "has_schema_privilege" at the SQL level. * They take various combinations of schema name, schema OID, * user name, user sysid, or implicit user = current_user. * * The result is a boolean value: true if user has the indicated * privilege, false if not. */ /* * has_schema_privilege_name_name * Check user privileges on a schema given * name username, text schemaname, and text priv name. */ Datum has_schema_privilege_name_name(PG_FUNCTION_ARGS) { Name username = PG_GETARG_NAME(0); text *schemaname = PG_GETARG_TEXT_P(1); text *priv_type_text = PG_GETARG_TEXT_P(2); int32 usesysid; Oid schemaoid; AclMode mode; AclResult aclresult; usesysid = get_usesysid(NameStr(*username)); schemaoid = convert_schema_name(schemaname); mode = convert_schema_priv_string(priv_type_text); aclresult = pg_namespace_aclcheck(schemaoid, usesysid, mode); PG_RETURN_BOOL(aclresult == ACLCHECK_OK); } /* * has_schema_privilege_name * Check user privileges on a schema given * text schemaname and text priv name. * current_user is assumed */ Datum has_schema_privilege_name(PG_FUNCTION_ARGS) { text *schemaname = PG_GETARG_TEXT_P(0); text *priv_type_text = PG_GETARG_TEXT_P(1); AclId usesysid; Oid schemaoid; AclMode mode; AclResult aclresult; usesysid = GetUserId(); schemaoid = convert_schema_name(schemaname); mode = convert_schema_priv_string(priv_type_text); aclresult = pg_namespace_aclcheck(schemaoid, usesysid, mode); PG_RETURN_BOOL(aclresult == ACLCHECK_OK); } /* * has_schema_privilege_name_id * Check user privileges on a schema given * name usename, schema oid, and text priv name. */ Datum has_schema_privilege_name_id(PG_FUNCTION_ARGS) { Name username = PG_GETARG_NAME(0); Oid schemaoid = PG_GETARG_OID(1); text *priv_type_text = PG_GETARG_TEXT_P(2); int32 usesysid; AclMode mode; AclResult aclresult; usesysid = get_usesysid(NameStr(*username)); mode = convert_schema_priv_string(priv_type_text); aclresult = pg_namespace_aclcheck(schemaoid, usesysid, mode); PG_RETURN_BOOL(aclresult == ACLCHECK_OK); } /* * has_schema_privilege_id * Check user privileges on a schema given * schema oid, and text priv name. * current_user is assumed */ Datum has_schema_privilege_id(PG_FUNCTION_ARGS) { Oid schemaoid = PG_GETARG_OID(0); text *priv_type_text = PG_GETARG_TEXT_P(1); AclId usesysid; AclMode mode; AclResult aclresult; usesysid = GetUserId(); mode = convert_schema_priv_string(priv_type_text); aclresult = pg_namespace_aclcheck(schemaoid, usesysid, mode); PG_RETURN_BOOL(aclresult == ACLCHECK_OK); } /* * has_schema_privilege_id_name * Check user privileges on a schema given * usesysid, text schemaname, and text priv name. */ Datum has_schema_privilege_id_name(PG_FUNCTION_ARGS) { int32 usesysid = PG_GETARG_INT32(0); text *schemaname = PG_GETARG_TEXT_P(1); text *priv_type_text = PG_GETARG_TEXT_P(2); Oid schemaoid; AclMode mode; AclResult aclresult; schemaoid = convert_schema_name(schemaname); mode = convert_schema_priv_string(priv_type_text); aclresult = pg_namespace_aclcheck(schemaoid, usesysid, mode); PG_RETURN_BOOL(aclresult == ACLCHECK_OK); } /* * has_schema_privilege_id_id * Check user privileges on a schema given * usesysid, schema oid, and text priv name. */ Datum has_schema_privilege_id_id(PG_FUNCTION_ARGS) { int32 usesysid = PG_GETARG_INT32(0); Oid schemaoid = PG_GETARG_OID(1); text *priv_type_text = PG_GETARG_TEXT_P(2); AclMode mode; AclResult aclresult; mode = convert_schema_priv_string(priv_type_text); aclresult = pg_namespace_aclcheck(schemaoid, usesysid, mode); PG_RETURN_BOOL(aclresult == ACLCHECK_OK); } /* * Support routines for has_schema_privilege family. */ /* * Given a schema name expressed as a string, look it up and return Oid */ static Oid convert_schema_name(text *schemaname) { char *nspname; Oid oid; nspname = DatumGetCString(DirectFunctionCall1(textout, PointerGetDatum(schemaname))); oid = GetSysCacheOid(NAMESPACENAME, CStringGetDatum(nspname), 0, 0, 0); if (!OidIsValid(oid)) ereport(ERROR, (errcode(ERRCODE_UNDEFINED_SCHEMA), errmsg("schema \"%s\" does not exist", nspname))); return oid; } /* * convert_schema_priv_string * Convert text string to AclMode value. */ static AclMode convert_schema_priv_string(text *priv_type_text) { char *priv_type; priv_type = DatumGetCString(DirectFunctionCall1(textout, PointerGetDatum(priv_type_text))); /* * Return mode from priv_type string */ if (strcasecmp(priv_type, "CREATE") == 0) return ACL_CREATE; if (strcasecmp(priv_type, "CREATE WITH GRANT OPTION") == 0) return ACL_GRANT_OPTION_FOR(ACL_CREATE); if (strcasecmp(priv_type, "USAGE") == 0) return ACL_USAGE; if (strcasecmp(priv_type, "USAGE WITH GRANT OPTION") == 0) return ACL_GRANT_OPTION_FOR(ACL_USAGE); ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), errmsg("unrecognized privilege type: \"%s\"", priv_type))); return ACL_NO_RIGHTS; /* keep compiler quiet */ }