PageRenderTime 38ms CodeModel.GetById 23ms RepoModel.GetById 1ms app.codeStats 0ms

/src/backend/utils/adt/acl.c

http://github.com/postgres/postgres
C | 5336 lines | 5268 code | 13 blank | 55 comment | 14 complexity | 94fd9eddf355cb89305484f139f889ca MD5 | raw file
Possible License(s): AGPL-3.0
  1. /*-------------------------------------------------------------------------
  2. *
  3. * acl.c
  4. * Basic access control list data structures manipulation routines.
  5. *
  6. * Portions Copyright (c) 1996-2020, PostgreSQL Global Development Group
  7. * Portions Copyright (c) 1994, Regents of the University of California
  8. *
  9. *
  10. * IDENTIFICATION
  11. * src/backend/utils/adt/acl.c
  12. *
  13. *-------------------------------------------------------------------------
  14. */
  15. #include "postgres.h"
  16. #include <ctype.h>
  17. #include "access/htup_details.h"
  18. #include "catalog/catalog.h"
  19. #include "catalog/namespace.h"
  20. #include "catalog/pg_auth_members.h"
  21. #include "catalog/pg_authid.h"
  22. #include "catalog/pg_class.h"
  23. #include "catalog/pg_type.h"
  24. #include "commands/dbcommands.h"
  25. #include "commands/proclang.h"
  26. #include "commands/tablespace.h"
  27. #include "common/hashfn.h"
  28. #include "foreign/foreign.h"
  29. #include "funcapi.h"
  30. #include "lib/qunique.h"
  31. #include "miscadmin.h"
  32. #include "utils/acl.h"
  33. #include "utils/array.h"
  34. #include "utils/builtins.h"
  35. #include "utils/catcache.h"
  36. #include "utils/inval.h"
  37. #include "utils/lsyscache.h"
  38. #include "utils/memutils.h"
  39. #include "utils/syscache.h"
  40. #include "utils/varlena.h"
  41. typedef struct
  42. {
  43. const char *name;
  44. AclMode value;
  45. } priv_map;
  46. /*
  47. * We frequently need to test whether a given role is a member of some other
  48. * role. In most of these tests the "given role" is the same, namely the
  49. * active current user. So we can optimize it by keeping a cached list of
  50. * all the roles the "given role" is a member of, directly or indirectly.
  51. * The cache is flushed whenever we detect a change in pg_auth_members.
  52. *
  53. * There are actually two caches, one computed under "has_privs" rules
  54. * (do not recurse where rolinherit isn't true) and one computed under
  55. * "is_member" rules (recurse regardless of rolinherit).
  56. *
  57. * Possibly this mechanism should be generalized to allow caching membership
  58. * info for multiple roles?
  59. *
  60. * The has_privs cache is:
  61. * cached_privs_role is the role OID the cache is for.
  62. * cached_privs_roles is an OID list of roles that cached_privs_role
  63. * has the privileges of (always including itself).
  64. * The cache is valid if cached_privs_role is not InvalidOid.
  65. *
  66. * The is_member cache is similarly:
  67. * cached_member_role is the role OID the cache is for.
  68. * cached_membership_roles is an OID list of roles that cached_member_role
  69. * is a member of (always including itself).
  70. * The cache is valid if cached_member_role is not InvalidOid.
  71. */
  72. static Oid cached_privs_role = InvalidOid;
  73. static List *cached_privs_roles = NIL;
  74. static Oid cached_member_role = InvalidOid;
  75. static List *cached_membership_roles = NIL;
  76. static const char *getid(const char *s, char *n);
  77. static void putid(char *p, const char *s);
  78. static Acl *allocacl(int n);
  79. static void check_acl(const Acl *acl);
  80. static const char *aclparse(const char *s, AclItem *aip);
  81. static bool aclitem_match(const AclItem *a1, const AclItem *a2);
  82. static int aclitemComparator(const void *arg1, const void *arg2);
  83. static void check_circularity(const Acl *old_acl, const AclItem *mod_aip,
  84. Oid ownerId);
  85. static Acl *recursive_revoke(Acl *acl, Oid grantee, AclMode revoke_privs,
  86. Oid ownerId, DropBehavior behavior);
  87. static AclMode convert_priv_string(text *priv_type_text);
  88. static AclMode convert_any_priv_string(text *priv_type_text,
  89. const priv_map *privileges);
  90. static Oid convert_table_name(text *tablename);
  91. static AclMode convert_table_priv_string(text *priv_type_text);
  92. static AclMode convert_sequence_priv_string(text *priv_type_text);
  93. static AttrNumber convert_column_name(Oid tableoid, text *column);
  94. static AclMode convert_column_priv_string(text *priv_type_text);
  95. static Oid convert_database_name(text *databasename);
  96. static AclMode convert_database_priv_string(text *priv_type_text);
  97. static Oid convert_foreign_data_wrapper_name(text *fdwname);
  98. static AclMode convert_foreign_data_wrapper_priv_string(text *priv_type_text);
  99. static Oid convert_function_name(text *functionname);
  100. static AclMode convert_function_priv_string(text *priv_type_text);
  101. static Oid convert_language_name(text *languagename);
  102. static AclMode convert_language_priv_string(text *priv_type_text);
  103. static Oid convert_schema_name(text *schemaname);
  104. static AclMode convert_schema_priv_string(text *priv_type_text);
  105. static Oid convert_server_name(text *servername);
  106. static AclMode convert_server_priv_string(text *priv_type_text);
  107. static Oid convert_tablespace_name(text *tablespacename);
  108. static AclMode convert_tablespace_priv_string(text *priv_type_text);
  109. static Oid convert_type_name(text *typename);
  110. static AclMode convert_type_priv_string(text *priv_type_text);
  111. static AclMode convert_role_priv_string(text *priv_type_text);
  112. static AclResult pg_role_aclcheck(Oid role_oid, Oid roleid, AclMode mode);
  113. static void RoleMembershipCacheCallback(Datum arg, int cacheid, uint32 hashvalue);
  114. /*
  115. * getid
  116. * Consumes the first alphanumeric string (identifier) found in string
  117. * 's', ignoring any leading white space. If it finds a double quote
  118. * it returns the word inside the quotes.
  119. *
  120. * RETURNS:
  121. * the string position in 's' that points to the next non-space character
  122. * in 's', after any quotes. Also:
  123. * - loads the identifier into 'n'. (If no identifier is found, 'n'
  124. * contains an empty string.) 'n' must be NAMEDATALEN bytes.
  125. */
  126. static const char *
  127. getid(const char *s, char *n)
  128. {
  129. int len = 0;
  130. bool in_quotes = false;
  131. Assert(s && n);
  132. while (isspace((unsigned char) *s))
  133. s++;
  134. /* This code had better match what putid() does, below */
  135. for (;
  136. *s != '\0' &&
  137. (isalnum((unsigned char) *s) ||
  138. *s == '_' ||
  139. *s == '"' ||
  140. in_quotes);
  141. s++)
  142. {
  143. if (*s == '"')
  144. {
  145. /* safe to look at next char (could be '\0' though) */
  146. if (*(s + 1) != '"')
  147. {
  148. in_quotes = !in_quotes;
  149. continue;
  150. }
  151. /* it's an escaped double quote; skip the escaping char */
  152. s++;
  153. }
  154. /* Add the character to the string */
  155. if (len >= NAMEDATALEN - 1)
  156. ereport(ERROR,
  157. (errcode(ERRCODE_NAME_TOO_LONG),
  158. errmsg("identifier too long"),
  159. errdetail("Identifier must be less than %d characters.",
  160. NAMEDATALEN)));
  161. n[len++] = *s;
  162. }
  163. n[len] = '\0';
  164. while (isspace((unsigned char) *s))
  165. s++;
  166. return s;
  167. }
  168. /*
  169. * Write a role name at *p, adding double quotes if needed.
  170. * There must be at least (2*NAMEDATALEN)+2 bytes available at *p.
  171. * This needs to be kept in sync with copyAclUserName in pg_dump/dumputils.c
  172. */
  173. static void
  174. putid(char *p, const char *s)
  175. {
  176. const char *src;
  177. bool safe = true;
  178. for (src = s; *src; src++)
  179. {
  180. /* This test had better match what getid() does, above */
  181. if (!isalnum((unsigned char) *src) && *src != '_')
  182. {
  183. safe = false;
  184. break;
  185. }
  186. }
  187. if (!safe)
  188. *p++ = '"';
  189. for (src = s; *src; src++)
  190. {
  191. /* A double quote character in a username is encoded as "" */
  192. if (*src == '"')
  193. *p++ = '"';
  194. *p++ = *src;
  195. }
  196. if (!safe)
  197. *p++ = '"';
  198. *p = '\0';
  199. }
  200. /*
  201. * aclparse
  202. * Consumes and parses an ACL specification of the form:
  203. * [group|user] [A-Za-z0-9]*=[rwaR]*
  204. * from string 's', ignoring any leading white space or white space
  205. * between the optional id type keyword (group|user) and the actual
  206. * ACL specification.
  207. *
  208. * The group|user decoration is unnecessary in the roles world,
  209. * but we still accept it for backward compatibility.
  210. *
  211. * This routine is called by the parser as well as aclitemin(), hence
  212. * the added generality.
  213. *
  214. * RETURNS:
  215. * the string position in 's' immediately following the ACL
  216. * specification. Also:
  217. * - loads the structure pointed to by 'aip' with the appropriate
  218. * UID/GID, id type identifier and mode type values.
  219. */
  220. static const char *
  221. aclparse(const char *s, AclItem *aip)
  222. {
  223. AclMode privs,
  224. goption,
  225. read;
  226. char name[NAMEDATALEN];
  227. char name2[NAMEDATALEN];
  228. Assert(s && aip);
  229. s = getid(s, name);
  230. if (*s != '=')
  231. {
  232. /* we just read a keyword, not a name */
  233. if (strcmp(name, "group") != 0 && strcmp(name, "user") != 0)
  234. ereport(ERROR,
  235. (errcode(ERRCODE_INVALID_TEXT_REPRESENTATION),
  236. errmsg("unrecognized key word: \"%s\"", name),
  237. errhint("ACL key word must be \"group\" or \"user\".")));
  238. s = getid(s, name); /* move s to the name beyond the keyword */
  239. if (name[0] == '\0')
  240. ereport(ERROR,
  241. (errcode(ERRCODE_INVALID_TEXT_REPRESENTATION),
  242. errmsg("missing name"),
  243. errhint("A name must follow the \"group\" or \"user\" key word.")));
  244. }
  245. if (*s != '=')
  246. ereport(ERROR,
  247. (errcode(ERRCODE_INVALID_TEXT_REPRESENTATION),
  248. errmsg("missing \"=\" sign")));
  249. privs = goption = ACL_NO_RIGHTS;
  250. for (++s, read = 0; isalpha((unsigned char) *s) || *s == '*'; s++)
  251. {
  252. switch (*s)
  253. {
  254. case '*':
  255. goption |= read;
  256. break;
  257. case ACL_INSERT_CHR:
  258. read = ACL_INSERT;
  259. break;
  260. case ACL_SELECT_CHR:
  261. read = ACL_SELECT;
  262. break;
  263. case ACL_UPDATE_CHR:
  264. read = ACL_UPDATE;
  265. break;
  266. case ACL_DELETE_CHR:
  267. read = ACL_DELETE;
  268. break;
  269. case ACL_TRUNCATE_CHR:
  270. read = ACL_TRUNCATE;
  271. break;
  272. case ACL_REFERENCES_CHR:
  273. read = ACL_REFERENCES;
  274. break;
  275. case ACL_TRIGGER_CHR:
  276. read = ACL_TRIGGER;
  277. break;
  278. case ACL_EXECUTE_CHR:
  279. read = ACL_EXECUTE;
  280. break;
  281. case ACL_USAGE_CHR:
  282. read = ACL_USAGE;
  283. break;
  284. case ACL_CREATE_CHR:
  285. read = ACL_CREATE;
  286. break;
  287. case ACL_CREATE_TEMP_CHR:
  288. read = ACL_CREATE_TEMP;
  289. break;
  290. case ACL_CONNECT_CHR:
  291. read = ACL_CONNECT;
  292. break;
  293. case 'R': /* ignore old RULE privileges */
  294. read = 0;
  295. break;
  296. default:
  297. ereport(ERROR,
  298. (errcode(ERRCODE_INVALID_TEXT_REPRESENTATION),
  299. errmsg("invalid mode character: must be one of \"%s\"",
  300. ACL_ALL_RIGHTS_STR)));
  301. }
  302. privs |= read;
  303. }
  304. if (name[0] == '\0')
  305. aip->ai_grantee = ACL_ID_PUBLIC;
  306. else
  307. aip->ai_grantee = get_role_oid(name, false);
  308. /*
  309. * XXX Allow a degree of backward compatibility by defaulting the grantor
  310. * to the superuser.
  311. */
  312. if (*s == '/')
  313. {
  314. s = getid(s + 1, name2);
  315. if (name2[0] == '\0')
  316. ereport(ERROR,
  317. (errcode(ERRCODE_INVALID_TEXT_REPRESENTATION),
  318. errmsg("a name must follow the \"/\" sign")));
  319. aip->ai_grantor = get_role_oid(name2, false);
  320. }
  321. else
  322. {
  323. aip->ai_grantor = BOOTSTRAP_SUPERUSERID;
  324. ereport(WARNING,
  325. (errcode(ERRCODE_INVALID_GRANTOR),
  326. errmsg("defaulting grantor to user ID %u",
  327. BOOTSTRAP_SUPERUSERID)));
  328. }
  329. ACLITEM_SET_PRIVS_GOPTIONS(*aip, privs, goption);
  330. return s;
  331. }
  332. /*
  333. * allocacl
  334. * Allocates storage for a new Acl with 'n' entries.
  335. *
  336. * RETURNS:
  337. * the new Acl
  338. */
  339. static Acl *
  340. allocacl(int n)
  341. {
  342. Acl *new_acl;
  343. Size size;
  344. if (n < 0)
  345. elog(ERROR, "invalid size: %d", n);
  346. size = ACL_N_SIZE(n);
  347. new_acl = (Acl *) palloc0(size);
  348. SET_VARSIZE(new_acl, size);
  349. new_acl->ndim = 1;
  350. new_acl->dataoffset = 0; /* we never put in any nulls */
  351. new_acl->elemtype = ACLITEMOID;
  352. ARR_LBOUND(new_acl)[0] = 1;
  353. ARR_DIMS(new_acl)[0] = n;
  354. return new_acl;
  355. }
  356. /*
  357. * Create a zero-entry ACL
  358. */
  359. Acl *
  360. make_empty_acl(void)
  361. {
  362. return allocacl(0);
  363. }
  364. /*
  365. * Copy an ACL
  366. */
  367. Acl *
  368. aclcopy(const Acl *orig_acl)
  369. {
  370. Acl *result_acl;
  371. result_acl = allocacl(ACL_NUM(orig_acl));
  372. memcpy(ACL_DAT(result_acl),
  373. ACL_DAT(orig_acl),
  374. ACL_NUM(orig_acl) * sizeof(AclItem));
  375. return result_acl;
  376. }
  377. /*
  378. * Concatenate two ACLs
  379. *
  380. * This is a bit cheesy, since we may produce an ACL with redundant entries.
  381. * Be careful what the result is used for!
  382. */
  383. Acl *
  384. aclconcat(const Acl *left_acl, const Acl *right_acl)
  385. {
  386. Acl *result_acl;
  387. result_acl = allocacl(ACL_NUM(left_acl) + ACL_NUM(right_acl));
  388. memcpy(ACL_DAT(result_acl),
  389. ACL_DAT(left_acl),
  390. ACL_NUM(left_acl) * sizeof(AclItem));
  391. memcpy(ACL_DAT(result_acl) + ACL_NUM(left_acl),
  392. ACL_DAT(right_acl),
  393. ACL_NUM(right_acl) * sizeof(AclItem));
  394. return result_acl;
  395. }
  396. /*
  397. * Merge two ACLs
  398. *
  399. * This produces a properly merged ACL with no redundant entries.
  400. * Returns NULL on NULL input.
  401. */
  402. Acl *
  403. aclmerge(const Acl *left_acl, const Acl *right_acl, Oid ownerId)
  404. {
  405. Acl *result_acl;
  406. AclItem *aip;
  407. int i,
  408. num;
  409. /* Check for cases where one or both are empty/null */
  410. if (left_acl == NULL || ACL_NUM(left_acl) == 0)
  411. {
  412. if (right_acl == NULL || ACL_NUM(right_acl) == 0)
  413. return NULL;
  414. else
  415. return aclcopy(right_acl);
  416. }
  417. else
  418. {
  419. if (right_acl == NULL || ACL_NUM(right_acl) == 0)
  420. return aclcopy(left_acl);
  421. }
  422. /* Merge them the hard way, one item at a time */
  423. result_acl = aclcopy(left_acl);
  424. aip = ACL_DAT(right_acl);
  425. num = ACL_NUM(right_acl);
  426. for (i = 0; i < num; i++, aip++)
  427. {
  428. Acl *tmp_acl;
  429. tmp_acl = aclupdate(result_acl, aip, ACL_MODECHG_ADD,
  430. ownerId, DROP_RESTRICT);
  431. pfree(result_acl);
  432. result_acl = tmp_acl;
  433. }
  434. return result_acl;
  435. }
  436. /*
  437. * Sort the items in an ACL (into an arbitrary but consistent order)
  438. */
  439. void
  440. aclitemsort(Acl *acl)
  441. {
  442. if (acl != NULL && ACL_NUM(acl) > 1)
  443. qsort(ACL_DAT(acl), ACL_NUM(acl), sizeof(AclItem), aclitemComparator);
  444. }
  445. /*
  446. * Check if two ACLs are exactly equal
  447. *
  448. * This will not detect equality if the two arrays contain the same items
  449. * in different orders. To handle that case, sort both inputs first,
  450. * using aclitemsort().
  451. */
  452. bool
  453. aclequal(const Acl *left_acl, const Acl *right_acl)
  454. {
  455. /* Check for cases where one or both are empty/null */
  456. if (left_acl == NULL || ACL_NUM(left_acl) == 0)
  457. {
  458. if (right_acl == NULL || ACL_NUM(right_acl) == 0)
  459. return true;
  460. else
  461. return false;
  462. }
  463. else
  464. {
  465. if (right_acl == NULL || ACL_NUM(right_acl) == 0)
  466. return false;
  467. }
  468. if (ACL_NUM(left_acl) != ACL_NUM(right_acl))
  469. return false;
  470. if (memcmp(ACL_DAT(left_acl),
  471. ACL_DAT(right_acl),
  472. ACL_NUM(left_acl) * sizeof(AclItem)) == 0)
  473. return true;
  474. return false;
  475. }
  476. /*
  477. * Verify that an ACL array is acceptable (one-dimensional and has no nulls)
  478. */
  479. static void
  480. check_acl(const Acl *acl)
  481. {
  482. if (ARR_ELEMTYPE(acl) != ACLITEMOID)
  483. ereport(ERROR,
  484. (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
  485. errmsg("ACL array contains wrong data type")));
  486. if (ARR_NDIM(acl) != 1)
  487. ereport(ERROR,
  488. (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
  489. errmsg("ACL arrays must be one-dimensional")));
  490. if (ARR_HASNULL(acl))
  491. ereport(ERROR,
  492. (errcode(ERRCODE_NULL_VALUE_NOT_ALLOWED),
  493. errmsg("ACL arrays must not contain null values")));
  494. }
  495. /*
  496. * aclitemin
  497. * Allocates storage for, and fills in, a new AclItem given a string
  498. * 's' that contains an ACL specification. See aclparse for details.
  499. *
  500. * RETURNS:
  501. * the new AclItem
  502. */
  503. Datum
  504. aclitemin(PG_FUNCTION_ARGS)
  505. {
  506. const char *s = PG_GETARG_CSTRING(0);
  507. AclItem *aip;
  508. aip = (AclItem *) palloc(sizeof(AclItem));
  509. s = aclparse(s, aip);
  510. while (isspace((unsigned char) *s))
  511. ++s;
  512. if (*s)
  513. ereport(ERROR,
  514. (errcode(ERRCODE_INVALID_TEXT_REPRESENTATION),
  515. errmsg("extra garbage at the end of the ACL specification")));
  516. PG_RETURN_ACLITEM_P(aip);
  517. }
  518. /*
  519. * aclitemout
  520. * Allocates storage for, and fills in, a new null-delimited string
  521. * containing a formatted ACL specification. See aclparse for details.
  522. *
  523. * RETURNS:
  524. * the new string
  525. */
  526. Datum
  527. aclitemout(PG_FUNCTION_ARGS)
  528. {
  529. AclItem *aip = PG_GETARG_ACLITEM_P(0);
  530. char *p;
  531. char *out;
  532. HeapTuple htup;
  533. unsigned i;
  534. out = palloc(strlen("=/") +
  535. 2 * N_ACL_RIGHTS +
  536. 2 * (2 * NAMEDATALEN + 2) +
  537. 1);
  538. p = out;
  539. *p = '\0';
  540. if (aip->ai_grantee != ACL_ID_PUBLIC)
  541. {
  542. htup = SearchSysCache1(AUTHOID, ObjectIdGetDatum(aip->ai_grantee));
  543. if (HeapTupleIsValid(htup))
  544. {
  545. putid(p, NameStr(((Form_pg_authid) GETSTRUCT(htup))->rolname));
  546. ReleaseSysCache(htup);
  547. }
  548. else
  549. {
  550. /* Generate numeric OID if we don't find an entry */
  551. sprintf(p, "%u", aip->ai_grantee);
  552. }
  553. }
  554. while (*p)
  555. ++p;
  556. *p++ = '=';
  557. for (i = 0; i < N_ACL_RIGHTS; ++i)
  558. {
  559. if (ACLITEM_GET_PRIVS(*aip) & (1 << i))
  560. *p++ = ACL_ALL_RIGHTS_STR[i];
  561. if (ACLITEM_GET_GOPTIONS(*aip) & (1 << i))
  562. *p++ = '*';
  563. }
  564. *p++ = '/';
  565. *p = '\0';
  566. htup = SearchSysCache1(AUTHOID, ObjectIdGetDatum(aip->ai_grantor));
  567. if (HeapTupleIsValid(htup))
  568. {
  569. putid(p, NameStr(((Form_pg_authid) GETSTRUCT(htup))->rolname));
  570. ReleaseSysCache(htup);
  571. }
  572. else
  573. {
  574. /* Generate numeric OID if we don't find an entry */
  575. sprintf(p, "%u", aip->ai_grantor);
  576. }
  577. PG_RETURN_CSTRING(out);
  578. }
  579. /*
  580. * aclitem_match
  581. * Two AclItems are considered to match iff they have the same
  582. * grantee and grantor; the privileges are ignored.
  583. */
  584. static bool
  585. aclitem_match(const AclItem *a1, const AclItem *a2)
  586. {
  587. return a1->ai_grantee == a2->ai_grantee &&
  588. a1->ai_grantor == a2->ai_grantor;
  589. }
  590. /*
  591. * aclitemComparator
  592. * qsort comparison function for AclItems
  593. */
  594. static int
  595. aclitemComparator(const void *arg1, const void *arg2)
  596. {
  597. const AclItem *a1 = (const AclItem *) arg1;
  598. const AclItem *a2 = (const AclItem *) arg2;
  599. if (a1->ai_grantee > a2->ai_grantee)
  600. return 1;
  601. if (a1->ai_grantee < a2->ai_grantee)
  602. return -1;
  603. if (a1->ai_grantor > a2->ai_grantor)
  604. return 1;
  605. if (a1->ai_grantor < a2->ai_grantor)
  606. return -1;
  607. if (a1->ai_privs > a2->ai_privs)
  608. return 1;
  609. if (a1->ai_privs < a2->ai_privs)
  610. return -1;
  611. return 0;
  612. }
  613. /*
  614. * aclitem equality operator
  615. */
  616. Datum
  617. aclitem_eq(PG_FUNCTION_ARGS)
  618. {
  619. AclItem *a1 = PG_GETARG_ACLITEM_P(0);
  620. AclItem *a2 = PG_GETARG_ACLITEM_P(1);
  621. bool result;
  622. result = a1->ai_privs == a2->ai_privs &&
  623. a1->ai_grantee == a2->ai_grantee &&
  624. a1->ai_grantor == a2->ai_grantor;
  625. PG_RETURN_BOOL(result);
  626. }
  627. /*
  628. * aclitem hash function
  629. *
  630. * We make aclitems hashable not so much because anyone is likely to hash
  631. * them, as because we want array equality to work on aclitem arrays, and
  632. * with the typcache mechanism we must have a hash or btree opclass.
  633. */
  634. Datum
  635. hash_aclitem(PG_FUNCTION_ARGS)
  636. {
  637. AclItem *a = PG_GETARG_ACLITEM_P(0);
  638. /* not very bright, but avoids any issue of padding in struct */
  639. PG_RETURN_UINT32((uint32) (a->ai_privs + a->ai_grantee + a->ai_grantor));
  640. }
  641. /*
  642. * 64-bit hash function for aclitem.
  643. *
  644. * Similar to hash_aclitem, but accepts a seed and returns a uint64 value.
  645. */
  646. Datum
  647. hash_aclitem_extended(PG_FUNCTION_ARGS)
  648. {
  649. AclItem *a = PG_GETARG_ACLITEM_P(0);
  650. uint64 seed = PG_GETARG_INT64(1);
  651. uint32 sum = (uint32) (a->ai_privs + a->ai_grantee + a->ai_grantor);
  652. return (seed == 0) ? UInt64GetDatum(sum) : hash_uint32_extended(sum, seed);
  653. }
  654. /*
  655. * acldefault() --- create an ACL describing default access permissions
  656. *
  657. * Change this routine if you want to alter the default access policy for
  658. * newly-created objects (or any object with a NULL acl entry). When
  659. * you make a change here, don't forget to update the GRANT man page,
  660. * which explains all the default permissions.
  661. *
  662. * Note that these are the hard-wired "defaults" that are used in the
  663. * absence of any pg_default_acl entry.
  664. */
  665. Acl *
  666. acldefault(ObjectType objtype, Oid ownerId)
  667. {
  668. AclMode world_default;
  669. AclMode owner_default;
  670. int nacl;
  671. Acl *acl;
  672. AclItem *aip;
  673. switch (objtype)
  674. {
  675. case OBJECT_COLUMN:
  676. /* by default, columns have no extra privileges */
  677. world_default = ACL_NO_RIGHTS;
  678. owner_default = ACL_NO_RIGHTS;
  679. break;
  680. case OBJECT_TABLE:
  681. world_default = ACL_NO_RIGHTS;
  682. owner_default = ACL_ALL_RIGHTS_RELATION;
  683. break;
  684. case OBJECT_SEQUENCE:
  685. world_default = ACL_NO_RIGHTS;
  686. owner_default = ACL_ALL_RIGHTS_SEQUENCE;
  687. break;
  688. case OBJECT_DATABASE:
  689. /* for backwards compatibility, grant some rights by default */
  690. world_default = ACL_CREATE_TEMP | ACL_CONNECT;
  691. owner_default = ACL_ALL_RIGHTS_DATABASE;
  692. break;
  693. case OBJECT_FUNCTION:
  694. /* Grant EXECUTE by default, for now */
  695. world_default = ACL_EXECUTE;
  696. owner_default = ACL_ALL_RIGHTS_FUNCTION;
  697. break;
  698. case OBJECT_LANGUAGE:
  699. /* Grant USAGE by default, for now */
  700. world_default = ACL_USAGE;
  701. owner_default = ACL_ALL_RIGHTS_LANGUAGE;
  702. break;
  703. case OBJECT_LARGEOBJECT:
  704. world_default = ACL_NO_RIGHTS;
  705. owner_default = ACL_ALL_RIGHTS_LARGEOBJECT;
  706. break;
  707. case OBJECT_SCHEMA:
  708. world_default = ACL_NO_RIGHTS;
  709. owner_default = ACL_ALL_RIGHTS_SCHEMA;
  710. break;
  711. case OBJECT_TABLESPACE:
  712. world_default = ACL_NO_RIGHTS;
  713. owner_default = ACL_ALL_RIGHTS_TABLESPACE;
  714. break;
  715. case OBJECT_FDW:
  716. world_default = ACL_NO_RIGHTS;
  717. owner_default = ACL_ALL_RIGHTS_FDW;
  718. break;
  719. case OBJECT_FOREIGN_SERVER:
  720. world_default = ACL_NO_RIGHTS;
  721. owner_default = ACL_ALL_RIGHTS_FOREIGN_SERVER;
  722. break;
  723. case OBJECT_DOMAIN:
  724. case OBJECT_TYPE:
  725. world_default = ACL_USAGE;
  726. owner_default = ACL_ALL_RIGHTS_TYPE;
  727. break;
  728. default:
  729. elog(ERROR, "unrecognized objtype: %d", (int) objtype);
  730. world_default = ACL_NO_RIGHTS; /* keep compiler quiet */
  731. owner_default = ACL_NO_RIGHTS;
  732. break;
  733. }
  734. nacl = 0;
  735. if (world_default != ACL_NO_RIGHTS)
  736. nacl++;
  737. if (owner_default != ACL_NO_RIGHTS)
  738. nacl++;
  739. acl = allocacl(nacl);
  740. aip = ACL_DAT(acl);
  741. if (world_default != ACL_NO_RIGHTS)
  742. {
  743. aip->ai_grantee = ACL_ID_PUBLIC;
  744. aip->ai_grantor = ownerId;
  745. ACLITEM_SET_PRIVS_GOPTIONS(*aip, world_default, ACL_NO_RIGHTS);
  746. aip++;
  747. }
  748. /*
  749. * Note that the owner's entry shows all ordinary privileges but no grant
  750. * options. This is because his grant options come "from the system" and
  751. * not from his own efforts. (The SQL spec says that the owner's rights
  752. * come from a "_SYSTEM" authid.) However, we do consider that the
  753. * owner's ordinary privileges are self-granted; this lets him revoke
  754. * them. We implement the owner's grant options without any explicit
  755. * "_SYSTEM"-like ACL entry, by internally special-casing the owner
  756. * wherever we are testing grant options.
  757. */
  758. if (owner_default != ACL_NO_RIGHTS)
  759. {
  760. aip->ai_grantee = ownerId;
  761. aip->ai_grantor = ownerId;
  762. ACLITEM_SET_PRIVS_GOPTIONS(*aip, owner_default, ACL_NO_RIGHTS);
  763. }
  764. return acl;
  765. }
  766. /*
  767. * SQL-accessible version of acldefault(). Hackish mapping from "char" type to
  768. * OBJECT_* values.
  769. */
  770. Datum
  771. acldefault_sql(PG_FUNCTION_ARGS)
  772. {
  773. char objtypec = PG_GETARG_CHAR(0);
  774. Oid owner = PG_GETARG_OID(1);
  775. ObjectType objtype = 0;
  776. switch (objtypec)
  777. {
  778. case 'c':
  779. objtype = OBJECT_COLUMN;
  780. break;
  781. case 'r':
  782. objtype = OBJECT_TABLE;
  783. break;
  784. case 's':
  785. objtype = OBJECT_SEQUENCE;
  786. break;
  787. case 'd':
  788. objtype = OBJECT_DATABASE;
  789. break;
  790. case 'f':
  791. objtype = OBJECT_FUNCTION;
  792. break;
  793. case 'l':
  794. objtype = OBJECT_LANGUAGE;
  795. break;
  796. case 'L':
  797. objtype = OBJECT_LARGEOBJECT;
  798. break;
  799. case 'n':
  800. objtype = OBJECT_SCHEMA;
  801. break;
  802. case 't':
  803. objtype = OBJECT_TABLESPACE;
  804. break;
  805. case 'F':
  806. objtype = OBJECT_FDW;
  807. break;
  808. case 'S':
  809. objtype = OBJECT_FOREIGN_SERVER;
  810. break;
  811. case 'T':
  812. objtype = OBJECT_TYPE;
  813. break;
  814. default:
  815. elog(ERROR, "unrecognized objtype abbreviation: %c", objtypec);
  816. }
  817. PG_RETURN_ACL_P(acldefault(objtype, owner));
  818. }
  819. /*
  820. * Update an ACL array to add or remove specified privileges.
  821. *
  822. * old_acl: the input ACL array
  823. * mod_aip: defines the privileges to be added, removed, or substituted
  824. * modechg: ACL_MODECHG_ADD, ACL_MODECHG_DEL, or ACL_MODECHG_EQL
  825. * ownerId: Oid of object owner
  826. * behavior: RESTRICT or CASCADE behavior for recursive removal
  827. *
  828. * ownerid and behavior are only relevant when the update operation specifies
  829. * deletion of grant options.
  830. *
  831. * The result is a modified copy; the input object is not changed.
  832. *
  833. * NB: caller is responsible for having detoasted the input ACL, if needed.
  834. */
  835. Acl *
  836. aclupdate(const Acl *old_acl, const AclItem *mod_aip,
  837. int modechg, Oid ownerId, DropBehavior behavior)
  838. {
  839. Acl *new_acl = NULL;
  840. AclItem *old_aip,
  841. *new_aip = NULL;
  842. AclMode old_rights,
  843. old_goptions,
  844. new_rights,
  845. new_goptions;
  846. int dst,
  847. num;
  848. /* Caller probably already checked old_acl, but be safe */
  849. check_acl(old_acl);
  850. /* If granting grant options, check for circularity */
  851. if (modechg != ACL_MODECHG_DEL &&
  852. ACLITEM_GET_GOPTIONS(*mod_aip) != ACL_NO_RIGHTS)
  853. check_circularity(old_acl, mod_aip, ownerId);
  854. num = ACL_NUM(old_acl);
  855. old_aip = ACL_DAT(old_acl);
  856. /*
  857. * Search the ACL for an existing entry for this grantee and grantor. If
  858. * one exists, just modify the entry in-place (well, in the same position,
  859. * since we actually return a copy); otherwise, insert the new entry at
  860. * the end.
  861. */
  862. for (dst = 0; dst < num; ++dst)
  863. {
  864. if (aclitem_match(mod_aip, old_aip + dst))
  865. {
  866. /* found a match, so modify existing item */
  867. new_acl = allocacl(num);
  868. new_aip = ACL_DAT(new_acl);
  869. memcpy(new_acl, old_acl, ACL_SIZE(old_acl));
  870. break;
  871. }
  872. }
  873. if (dst == num)
  874. {
  875. /* need to append a new item */
  876. new_acl = allocacl(num + 1);
  877. new_aip = ACL_DAT(new_acl);
  878. memcpy(new_aip, old_aip, num * sizeof(AclItem));
  879. /* initialize the new entry with no permissions */
  880. new_aip[dst].ai_grantee = mod_aip->ai_grantee;
  881. new_aip[dst].ai_grantor = mod_aip->ai_grantor;
  882. ACLITEM_SET_PRIVS_GOPTIONS(new_aip[dst],
  883. ACL_NO_RIGHTS, ACL_NO_RIGHTS);
  884. num++; /* set num to the size of new_acl */
  885. }
  886. old_rights = ACLITEM_GET_RIGHTS(new_aip[dst]);
  887. old_goptions = ACLITEM_GET_GOPTIONS(new_aip[dst]);
  888. /* apply the specified permissions change */
  889. switch (modechg)
  890. {
  891. case ACL_MODECHG_ADD:
  892. ACLITEM_SET_RIGHTS(new_aip[dst],
  893. old_rights | ACLITEM_GET_RIGHTS(*mod_aip));
  894. break;
  895. case ACL_MODECHG_DEL:
  896. ACLITEM_SET_RIGHTS(new_aip[dst],
  897. old_rights & ~ACLITEM_GET_RIGHTS(*mod_aip));
  898. break;
  899. case ACL_MODECHG_EQL:
  900. ACLITEM_SET_RIGHTS(new_aip[dst],
  901. ACLITEM_GET_RIGHTS(*mod_aip));
  902. break;
  903. }
  904. new_rights = ACLITEM_GET_RIGHTS(new_aip[dst]);
  905. new_goptions = ACLITEM_GET_GOPTIONS(new_aip[dst]);
  906. /*
  907. * If the adjusted entry has no permissions, delete it from the list.
  908. */
  909. if (new_rights == ACL_NO_RIGHTS)
  910. {
  911. memmove(new_aip + dst,
  912. new_aip + dst + 1,
  913. (num - dst - 1) * sizeof(AclItem));
  914. /* Adjust array size to be 'num - 1' items */
  915. ARR_DIMS(new_acl)[0] = num - 1;
  916. SET_VARSIZE(new_acl, ACL_N_SIZE(num - 1));
  917. }
  918. /*
  919. * Remove abandoned privileges (cascading revoke). Currently we can only
  920. * handle this when the grantee is not PUBLIC.
  921. */
  922. if ((old_goptions & ~new_goptions) != 0)
  923. {
  924. Assert(mod_aip->ai_grantee != ACL_ID_PUBLIC);
  925. new_acl = recursive_revoke(new_acl, mod_aip->ai_grantee,
  926. (old_goptions & ~new_goptions),
  927. ownerId, behavior);
  928. }
  929. return new_acl;
  930. }
  931. /*
  932. * Update an ACL array to reflect a change of owner to the parent object
  933. *
  934. * old_acl: the input ACL array (must not be NULL)
  935. * oldOwnerId: Oid of the old object owner
  936. * newOwnerId: Oid of the new object owner
  937. *
  938. * The result is a modified copy; the input object is not changed.
  939. *
  940. * NB: caller is responsible for having detoasted the input ACL, if needed.
  941. */
  942. Acl *
  943. aclnewowner(const Acl *old_acl, Oid oldOwnerId, Oid newOwnerId)
  944. {
  945. Acl *new_acl;
  946. AclItem *new_aip;
  947. AclItem *old_aip;
  948. AclItem *dst_aip;
  949. AclItem *src_aip;
  950. AclItem *targ_aip;
  951. bool newpresent = false;
  952. int dst,
  953. src,
  954. targ,
  955. num;
  956. check_acl(old_acl);
  957. /*
  958. * Make a copy of the given ACL, substituting new owner ID for old
  959. * wherever it appears as either grantor or grantee. Also note if the new
  960. * owner ID is already present.
  961. */
  962. num = ACL_NUM(old_acl);
  963. old_aip = ACL_DAT(old_acl);
  964. new_acl = allocacl(num);
  965. new_aip = ACL_DAT(new_acl);
  966. memcpy(new_aip, old_aip, num * sizeof(AclItem));
  967. for (dst = 0, dst_aip = new_aip; dst < num; dst++, dst_aip++)
  968. {
  969. if (dst_aip->ai_grantor == oldOwnerId)
  970. dst_aip->ai_grantor = newOwnerId;
  971. else if (dst_aip->ai_grantor == newOwnerId)
  972. newpresent = true;
  973. if (dst_aip->ai_grantee == oldOwnerId)
  974. dst_aip->ai_grantee = newOwnerId;
  975. else if (dst_aip->ai_grantee == newOwnerId)
  976. newpresent = true;
  977. }
  978. /*
  979. * If the old ACL contained any references to the new owner, then we may
  980. * now have generated an ACL containing duplicate entries. Find them and
  981. * merge them so that there are not duplicates. (This is relatively
  982. * expensive since we use a stupid O(N^2) algorithm, but it's unlikely to
  983. * be the normal case.)
  984. *
  985. * To simplify deletion of duplicate entries, we temporarily leave them in
  986. * the array but set their privilege masks to zero; when we reach such an
  987. * entry it's just skipped. (Thus, a side effect of this code will be to
  988. * remove privilege-free entries, should there be any in the input.) dst
  989. * is the next output slot, targ is the currently considered input slot
  990. * (always >= dst), and src scans entries to the right of targ looking for
  991. * duplicates. Once an entry has been emitted to dst it is known
  992. * duplicate-free and need not be considered anymore.
  993. */
  994. if (newpresent)
  995. {
  996. dst = 0;
  997. for (targ = 0, targ_aip = new_aip; targ < num; targ++, targ_aip++)
  998. {
  999. /* ignore if deleted in an earlier pass */
  1000. if (ACLITEM_GET_RIGHTS(*targ_aip) == ACL_NO_RIGHTS)
  1001. continue;
  1002. /* find and merge any duplicates */
  1003. for (src = targ + 1, src_aip = targ_aip + 1; src < num;
  1004. src++, src_aip++)
  1005. {
  1006. if (ACLITEM_GET_RIGHTS(*src_aip) == ACL_NO_RIGHTS)
  1007. continue;
  1008. if (aclitem_match(targ_aip, src_aip))
  1009. {
  1010. ACLITEM_SET_RIGHTS(*targ_aip,
  1011. ACLITEM_GET_RIGHTS(*targ_aip) |
  1012. ACLITEM_GET_RIGHTS(*src_aip));
  1013. /* mark the duplicate deleted */
  1014. ACLITEM_SET_RIGHTS(*src_aip, ACL_NO_RIGHTS);
  1015. }
  1016. }
  1017. /* and emit to output */
  1018. new_aip[dst] = *targ_aip;
  1019. dst++;
  1020. }
  1021. /* Adjust array size to be 'dst' items */
  1022. ARR_DIMS(new_acl)[0] = dst;
  1023. SET_VARSIZE(new_acl, ACL_N_SIZE(dst));
  1024. }
  1025. return new_acl;
  1026. }
  1027. /*
  1028. * When granting grant options, we must disallow attempts to set up circular
  1029. * chains of grant options. Suppose A (the object owner) grants B some
  1030. * privileges with grant option, and B re-grants them to C. If C could
  1031. * grant the privileges to B as well, then A would be unable to effectively
  1032. * revoke the privileges from B, since recursive_revoke would consider that
  1033. * B still has 'em from C.
  1034. *
  1035. * We check for this by recursively deleting all grant options belonging to
  1036. * the target grantee, and then seeing if the would-be grantor still has the
  1037. * grant option or not.
  1038. */
  1039. static void
  1040. check_circularity(const Acl *old_acl, const AclItem *mod_aip,
  1041. Oid ownerId)
  1042. {
  1043. Acl *acl;
  1044. AclItem *aip;
  1045. int i,
  1046. num;
  1047. AclMode own_privs;
  1048. check_acl(old_acl);
  1049. /*
  1050. * For now, grant options can only be granted to roles, not PUBLIC.
  1051. * Otherwise we'd have to work a bit harder here.
  1052. */
  1053. Assert(mod_aip->ai_grantee != ACL_ID_PUBLIC);
  1054. /* The owner always has grant options, no need to check */
  1055. if (mod_aip->ai_grantor == ownerId)
  1056. return;
  1057. /* Make a working copy */
  1058. acl = allocacl(ACL_NUM(old_acl));
  1059. memcpy(acl, old_acl, ACL_SIZE(old_acl));
  1060. /* Zap all grant options of target grantee, plus what depends on 'em */
  1061. cc_restart:
  1062. num = ACL_NUM(acl);
  1063. aip = ACL_DAT(acl);
  1064. for (i = 0; i < num; i++)
  1065. {
  1066. if (aip[i].ai_grantee == mod_aip->ai_grantee &&
  1067. ACLITEM_GET_GOPTIONS(aip[i]) != ACL_NO_RIGHTS)
  1068. {
  1069. Acl *new_acl;
  1070. /* We'll actually zap ordinary privs too, but no matter */
  1071. new_acl = aclupdate(acl, &aip[i], ACL_MODECHG_DEL,
  1072. ownerId, DROP_CASCADE);
  1073. pfree(acl);
  1074. acl = new_acl;
  1075. goto cc_restart;
  1076. }
  1077. }
  1078. /* Now we can compute grantor's independently-derived privileges */
  1079. own_privs = aclmask(acl,
  1080. mod_aip->ai_grantor,
  1081. ownerId,
  1082. ACL_GRANT_OPTION_FOR(ACLITEM_GET_GOPTIONS(*mod_aip)),
  1083. ACLMASK_ALL);
  1084. own_privs = ACL_OPTION_TO_PRIVS(own_privs);
  1085. if ((ACLITEM_GET_GOPTIONS(*mod_aip) & ~own_privs) != 0)
  1086. ereport(ERROR,
  1087. (errcode(ERRCODE_INVALID_GRANT_OPERATION),
  1088. errmsg("grant options cannot be granted back to your own grantor")));
  1089. pfree(acl);
  1090. }
  1091. /*
  1092. * Ensure that no privilege is "abandoned". A privilege is abandoned
  1093. * if the user that granted the privilege loses the grant option. (So
  1094. * the chain through which it was granted is broken.) Either the
  1095. * abandoned privileges are revoked as well, or an error message is
  1096. * printed, depending on the drop behavior option.
  1097. *
  1098. * acl: the input ACL list
  1099. * grantee: the user from whom some grant options have been revoked
  1100. * revoke_privs: the grant options being revoked
  1101. * ownerId: Oid of object owner
  1102. * behavior: RESTRICT or CASCADE behavior for recursive removal
  1103. *
  1104. * The input Acl object is pfree'd if replaced.
  1105. */
  1106. static Acl *
  1107. recursive_revoke(Acl *acl,
  1108. Oid grantee,
  1109. AclMode revoke_privs,
  1110. Oid ownerId,
  1111. DropBehavior behavior)
  1112. {
  1113. AclMode still_has;
  1114. AclItem *aip;
  1115. int i,
  1116. num;
  1117. check_acl(acl);
  1118. /* The owner can never truly lose grant options, so short-circuit */
  1119. if (grantee == ownerId)
  1120. return acl;
  1121. /* The grantee might still have some grant options via another grantor */
  1122. still_has = aclmask(acl, grantee, ownerId,
  1123. ACL_GRANT_OPTION_FOR(revoke_privs),
  1124. ACLMASK_ALL);
  1125. revoke_privs &= ~ACL_OPTION_TO_PRIVS(still_has);
  1126. if (revoke_privs == ACL_NO_RIGHTS)
  1127. return acl;
  1128. restart:
  1129. num = ACL_NUM(acl);
  1130. aip = ACL_DAT(acl);
  1131. for (i = 0; i < num; i++)
  1132. {
  1133. if (aip[i].ai_grantor == grantee
  1134. && (ACLITEM_GET_PRIVS(aip[i]) & revoke_privs) != 0)
  1135. {
  1136. AclItem mod_acl;
  1137. Acl *new_acl;
  1138. if (behavior == DROP_RESTRICT)
  1139. ereport(ERROR,
  1140. (errcode(ERRCODE_DEPENDENT_OBJECTS_STILL_EXIST),
  1141. errmsg("dependent privileges exist"),
  1142. errhint("Use CASCADE to revoke them too.")));
  1143. mod_acl.ai_grantor = grantee;
  1144. mod_acl.ai_grantee = aip[i].ai_grantee;
  1145. ACLITEM_SET_PRIVS_GOPTIONS(mod_acl,
  1146. revoke_privs,
  1147. revoke_privs);
  1148. new_acl = aclupdate(acl, &mod_acl, ACL_MODECHG_DEL,
  1149. ownerId, behavior);
  1150. pfree(acl);
  1151. acl = new_acl;
  1152. goto restart;
  1153. }
  1154. }
  1155. return acl;
  1156. }
  1157. /*
  1158. * aclmask --- compute bitmask of all privileges held by roleid.
  1159. *
  1160. * When 'how' = ACLMASK_ALL, this simply returns the privilege bits
  1161. * held by the given roleid according to the given ACL list, ANDed
  1162. * with 'mask'. (The point of passing 'mask' is to let the routine
  1163. * exit early if all privileges of interest have been found.)
  1164. *
  1165. * When 'how' = ACLMASK_ANY, returns as soon as any bit in the mask
  1166. * is known true. (This lets us exit soonest in cases where the
  1167. * caller is only going to test for zero or nonzero result.)
  1168. *
  1169. * Usage patterns:
  1170. *
  1171. * To see if any of a set of privileges are held:
  1172. * if (aclmask(acl, roleid, ownerId, privs, ACLMASK_ANY) != 0)
  1173. *
  1174. * To see if all of a set of privileges are held:
  1175. * if (aclmask(acl, roleid, ownerId, privs, ACLMASK_ALL) == privs)
  1176. *
  1177. * To determine exactly which of a set of privileges are held:
  1178. * heldprivs = aclmask(acl, roleid, ownerId, privs, ACLMASK_ALL);
  1179. */
  1180. AclMode
  1181. aclmask(const Acl *acl, Oid roleid, Oid ownerId,
  1182. AclMode mask, AclMaskHow how)
  1183. {
  1184. AclMode result;
  1185. AclMode remaining;
  1186. AclItem *aidat;
  1187. int i,
  1188. num;
  1189. /*
  1190. * Null ACL should not happen, since caller should have inserted
  1191. * appropriate default
  1192. */
  1193. if (acl == NULL)
  1194. elog(ERROR, "null ACL");
  1195. check_acl(acl);
  1196. /* Quick exit for mask == 0 */
  1197. if (mask == 0)
  1198. return 0;
  1199. result = 0;
  1200. /* Owner always implicitly has all grant options */
  1201. if ((mask & ACLITEM_ALL_GOPTION_BITS) &&
  1202. has_privs_of_role(roleid, ownerId))
  1203. {
  1204. result = mask & ACLITEM_ALL_GOPTION_BITS;
  1205. if ((how == ACLMASK_ALL) ? (result == mask) : (result != 0))
  1206. return result;
  1207. }
  1208. num = ACL_NUM(acl);
  1209. aidat = ACL_DAT(acl);
  1210. /*
  1211. * Check privileges granted directly to roleid or to public
  1212. */
  1213. for (i = 0; i < num; i++)
  1214. {
  1215. AclItem *aidata = &aidat[i];
  1216. if (aidata->ai_grantee == ACL_ID_PUBLIC ||
  1217. aidata->ai_grantee == roleid)
  1218. {
  1219. result |= aidata->ai_privs & mask;
  1220. if ((how == ACLMASK_ALL) ? (result == mask) : (result != 0))
  1221. return result;
  1222. }
  1223. }
  1224. /*
  1225. * Check privileges granted indirectly via role memberships. We do this in
  1226. * a separate pass to minimize expensive indirect membership tests. In
  1227. * particular, it's worth testing whether a given ACL entry grants any
  1228. * privileges still of interest before we perform the has_privs_of_role
  1229. * test.
  1230. */
  1231. remaining = mask & ~result;
  1232. for (i = 0; i < num; i++)
  1233. {
  1234. AclItem *aidata = &aidat[i];
  1235. if (aidata->ai_grantee == ACL_ID_PUBLIC ||
  1236. aidata->ai_grantee == roleid)
  1237. continue; /* already checked it */
  1238. if ((aidata->ai_privs & remaining) &&
  1239. has_privs_of_role(roleid, aidata->ai_grantee))
  1240. {
  1241. result |= aidata->ai_privs & mask;
  1242. if ((how == ACLMASK_ALL) ? (result == mask) : (result != 0))
  1243. return result;
  1244. remaining = mask & ~result;
  1245. }
  1246. }
  1247. return result;
  1248. }
  1249. /*
  1250. * aclmask_direct --- compute bitmask of all privileges held by roleid.
  1251. *
  1252. * This is exactly like aclmask() except that we consider only privileges
  1253. * held *directly* by roleid, not those inherited via role membership.
  1254. */
  1255. static AclMode
  1256. aclmask_direct(const Acl *acl, Oid roleid, Oid ownerId,
  1257. AclMode mask, AclMaskHow how)
  1258. {
  1259. AclMode result;
  1260. AclItem *aidat;
  1261. int i,
  1262. num;
  1263. /*
  1264. * Null ACL should not happen, since caller should have inserted
  1265. * appropriate default
  1266. */
  1267. if (acl == NULL)
  1268. elog(ERROR, "null ACL");
  1269. check_acl(acl);
  1270. /* Quick exit for mask == 0 */
  1271. if (mask == 0)
  1272. return 0;
  1273. result = 0;
  1274. /* Owner always implicitly has all grant options */
  1275. if ((mask & ACLITEM_ALL_GOPTION_BITS) &&
  1276. roleid == ownerId)
  1277. {
  1278. result = mask & ACLITEM_ALL_GOPTION_BITS;
  1279. if ((how == ACLMASK_ALL) ? (result == mask) : (result != 0))
  1280. return result;
  1281. }
  1282. num = ACL_NUM(acl);
  1283. aidat = ACL_DAT(acl);
  1284. /*
  1285. * Check privileges granted directly to roleid (and not to public)
  1286. */
  1287. for (i = 0; i < num; i++)
  1288. {
  1289. AclItem *aidata = &aidat[i];
  1290. if (aidata->ai_grantee == roleid)
  1291. {
  1292. result |= aidata->ai_privs & mask;
  1293. if ((how == ACLMASK_ALL) ? (result == mask) : (result != 0))
  1294. return result;
  1295. }
  1296. }
  1297. return result;
  1298. }
  1299. /*
  1300. * aclmembers
  1301. * Find out all the roleids mentioned in an Acl.
  1302. * Note that we do not distinguish grantors from grantees.
  1303. *
  1304. * *roleids is set to point to a palloc'd array containing distinct OIDs
  1305. * in sorted order. The length of the array is the function result.
  1306. */
  1307. int
  1308. aclmembers(const Acl *acl, Oid **roleids)
  1309. {
  1310. Oid *list;
  1311. const AclItem *acldat;
  1312. int i,
  1313. j;
  1314. if (acl == NULL || ACL_NUM(acl) == 0)
  1315. {
  1316. *roleids = NULL;
  1317. return 0;
  1318. }
  1319. check_acl(acl);
  1320. /* Allocate the worst-case space requirement */
  1321. list = palloc(ACL_NUM(acl) * 2 * sizeof(Oid));
  1322. acldat = ACL_DAT(acl);
  1323. /*
  1324. * Walk the ACL collecting mentioned RoleIds.
  1325. */
  1326. j = 0;
  1327. for (i = 0; i < ACL_NUM(acl); i++)
  1328. {
  1329. const AclItem *ai = &acldat[i];
  1330. if (ai->ai_grantee != ACL_ID_PUBLIC)
  1331. list[j++] = ai->ai_grantee;
  1332. /* grantor is currently never PUBLIC, but let's check anyway */
  1333. if (ai->ai_grantor != ACL_ID_PUBLIC)
  1334. list[j++] = ai->ai_grantor;
  1335. }
  1336. /* Sort the array */
  1337. qsort(list, j, sizeof(Oid), oid_cmp);
  1338. /*
  1339. * We could repalloc the array down to minimum size, but it's hardly worth
  1340. * it since it's only transient memory.
  1341. */
  1342. *roleids = list;
  1343. /* Remove duplicates from the array */
  1344. return qunique(list, j, sizeof(Oid), oid_cmp);
  1345. }
  1346. /*
  1347. * aclinsert (exported function)
  1348. */
  1349. Datum
  1350. aclinsert(PG_FUNCTION_ARGS)
  1351. {
  1352. ereport(ERROR,
  1353. (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
  1354. errmsg("aclinsert is no longer supported")));
  1355. PG_RETURN_NULL(); /* keep compiler quiet */
  1356. }
  1357. Datum
  1358. aclremove(PG_FUNCTION_ARGS)
  1359. {
  1360. ereport(ERROR,
  1361. (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
  1362. errmsg("aclremove is no longer supported")));
  1363. PG_RETURN_NULL(); /* keep compiler quiet */
  1364. }
  1365. Datum
  1366. aclcontains(PG_FUNCTION_ARGS)
  1367. {
  1368. Acl *acl = PG_GETARG_ACL_P(0);
  1369. AclItem *aip = PG_GETARG_ACLITEM_P(1);
  1370. AclItem *aidat;
  1371. int i,
  1372. num;
  1373. check_acl(acl);
  1374. num = ACL_NUM(acl);
  1375. aidat = ACL_DAT(acl);
  1376. for (i = 0; i < num; ++i)
  1377. {
  1378. if (aip->ai_grantee == aidat[i].ai_grantee &&
  1379. aip->ai_grantor == aidat[i].ai_grantor &&
  1380. (ACLITEM_GET_RIGHTS(*aip) & ACLITEM_GET_RIGHTS(aidat[i])) == ACLITEM_GET_RIGHTS(*aip))
  1381. PG_RETURN_BOOL(true);
  1382. }
  1383. PG_RETURN_BOOL(false);
  1384. }
  1385. Datum
  1386. makeaclitem(PG_FUNCTION_ARGS)
  1387. {
  1388. Oid grantee = PG_GETARG_OID(0);
  1389. Oid grantor = PG_GETARG_OID(1);
  1390. text *privtext = PG_GETARG_TEXT_PP(2);
  1391. bool goption = PG_GETARG_BOOL(3);
  1392. AclItem *result;
  1393. AclMode priv;
  1394. priv = convert_priv_string(privtext);
  1395. result = (AclItem *) palloc(sizeof(AclItem));
  1396. result->ai_grantee = grantee;
  1397. result->ai_grantor = grantor;
  1398. ACLITEM_SET_PRIVS_GOPTIONS(*result, priv,
  1399. (goption ? priv : ACL_NO_RIGHTS));
  1400. PG_RETURN_ACLITEM_P(result);
  1401. }
  1402. static AclMode
  1403. convert_priv_string(text *priv_type_text)
  1404. {
  1405. char *priv_type = text_to_cstring(priv_type_text);
  1406. if (pg_strcasecmp(priv_type, "SELECT") == 0)
  1407. return ACL_SELECT;
  1408. if (pg_strcasecmp(priv_type, "INSERT") == 0)
  1409. return ACL_INSERT;
  1410. if (pg_strcasecmp(priv_type, "UPDATE") == 0)
  1411. return ACL_UPDATE;
  1412. if (pg_strcasecmp(priv_type, "DELETE") == 0)
  1413. return ACL_DELETE;
  1414. if (pg_strcasecmp(priv_type, "TRUNCATE") == 0)
  1415. return ACL_TRUNCATE;
  1416. if (pg_strcasecmp(priv_type, "REFERENCES") == 0)
  1417. return ACL_REFERENCES;
  1418. if (pg_strcasecmp(priv_type, "TRIGGER") == 0)
  1419. return ACL_TRIGGER;
  1420. if (pg_strcasecmp(priv_type, "EXECUTE") == 0)
  1421. return ACL_EXECUTE;
  1422. if (pg_strcasecmp(priv_type, "USAGE") == 0)
  1423. return ACL_USAGE;
  1424. if (pg_strcasecmp(priv_type, "CREATE") == 0)
  1425. return ACL_CREATE;
  1426. if (pg_strcasecmp(priv_type, "TEMP") == 0)
  1427. return ACL_CREATE_TEMP;
  1428. if (pg_strcasecmp(priv_type, "TEMPORARY") == 0)
  1429. return ACL_CREATE_TEMP;
  1430. if (pg_strcasecmp(priv_type, "CONNECT") == 0)
  1431. return ACL_CONNECT;
  1432. if (pg_strcasecmp(priv_type, "RULE") == 0)
  1433. return 0; /* ignore old RULE privileges */
  1434. ereport(ERROR,
  1435. (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
  1436. errmsg("unrecognized privilege type: \"%s\"", priv_type)));
  1437. return ACL_NO_RIGHTS; /* keep compiler quiet */
  1438. }
  1439. /*
  1440. * convert_any_priv_string: recognize privilege strings for has_foo_privilege
  1441. *
  1442. * We accept a comma-separated list of case-insensitive privilege names,
  1443. * producing a bitmask of the OR'd privilege bits. We are liberal about
  1444. * whitespace between items, not so much about whitespace within items.
  1445. * The allowed privilege names are given as an array of priv_map structs,
  1446. * terminated by one with a NULL name pointer.
  1447. */
  1448. static AclMode
  1449. convert_any_priv_string(text *priv_type_text,
  1450. const priv_map *privileges)
  1451. {
  1452. AclMode result = 0;
  1453. char *priv_type = text_to_cstring(priv_type_text);
  1454. char *chunk;
  1455. char *next_chunk;
  1456. /* We rely on priv_type being a private, modifiable string */
  1457. for (chunk = priv_type; chunk; chunk = next_chunk)
  1458. {
  1459. int chunk_len;
  1460. const priv_map *this_priv;
  1461. /* Split string at commas */
  1462. next_chunk = strchr(chunk, ',');
  1463. if (next_chunk)
  1464. *next_chunk++ = '\0';
  1465. /* Drop leading/trailing whitespace in this chunk */
  1466. while (*chunk && isspace((unsigned char) *chunk))
  1467. chunk++;
  1468. chunk_len = strlen(chunk);
  1469. while (chunk_len > 0 && isspace((unsigned char) chunk[chunk_len - 1]))
  1470. chunk_len--;
  1471. chunk[chunk_len] = '\0';
  1472. /* Match to the privileges list */
  1473. for (this_priv = privileges; this_priv->name; this_priv++)
  1474. {
  1475. if (pg_strcasecmp(this_priv->name, chunk) == 0)
  1476. {
  1477. result |= this_priv->value;
  1478. break;
  1479. }
  1480. }
  1481. if (!this_priv->name)
  1482. ereport(ERROR,
  1483. (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
  1484. errmsg("unrecognized privilege type: \"%s\"", chunk)));
  1485. }
  1486. pfree(priv_type);
  1487. return result;
  1488. }
  1489. static const char *
  1490. convert_aclright_to_string(int aclright)
  1491. {
  1492. switch (aclright)
  1493. {
  1494. case ACL_INSERT:
  1495. return "INSERT";
  1496. case ACL_SELECT:
  1497. return "SELECT";
  1498. case ACL_UPDATE:
  1499. return "UPDATE";
  1500. case ACL_DELETE:
  1501. return "DELETE";
  1502. case ACL_TRUNCATE:
  1503. return "TRUNCATE";
  1504. case ACL_REFERENCES:
  1505. return "REFERENCES";
  1506. case ACL_TRIGGER:
  1507. return "TRIGGER";
  1508. case ACL_EXECUTE:
  1509. return "EXECUTE";
  1510. case ACL_USAGE:
  1511. return "USAGE";
  1512. case ACL_CREATE:
  1513. return "CREATE";
  1514. case ACL_CREATE_TEMP:
  1515. return "TEMPORARY";
  1516. case ACL_CONNECT:
  1517. return "CONNECT";
  1518. default:
  1519. elog(ERROR, "unrecognized aclright: %d", aclright);
  1520. return NULL;
  1521. }
  1522. }
  1523. /*----------
  1524. * Convert an aclitem[] to a table.
  1525. *
  1526. * Example:
  1527. *
  1528. * aclexplode('{=r/joe,foo=a*w/joe}'::aclitem[])
  1529. *
  1530. * returns the table
  1531. *
  1532. * {{ OID(joe), 0::OID, 'SELECT', false },
  1533. * { OID(joe), OID(foo), 'INSERT', true },
  1534. * { OID(joe), OID(foo), 'UPDATE', false }}
  1535. *----------
  1536. */
  1537. Datum
  1538. aclexplode(PG_FUNCTION_ARGS)
  1539. {
  1540. Acl *acl = PG_GETARG_ACL_P(0);
  1541. FuncCallContext *funcctx;
  1542. int *idx;
  1543. AclItem *aidat;
  1544. if (SRF_IS_FIRSTCALL())
  1545. {
  1546. TupleDesc tupdesc;
  1547. MemoryContext oldcontext;
  1548. check_acl(acl);
  1549. funcctx = SRF_FIRSTCALL_INIT();
  1550. oldcontext = MemoryContextSwitchTo(funcctx->multi_call_memory_ctx);
  1551. /*
  1552. * build tupdesc for result tuples (matches out parameters in pg_proc
  1553. * entry)
  1554. */
  1555. tupdesc = CreateTemplateTupleDesc(4);
  1556. TupleDescInitEntry(tupdesc, (AttrNumber) 1, "grantor",
  1557. OIDOID, -1, 0);
  1558. TupleDescInitEntry(tupdesc, (AttrNumber) 2, "grantee",
  1559. OIDOID, -1, 0);
  1560. TupleDescInitEntry(tupdesc, (AttrNumber) 3, "privilege_type",
  1561. TEXTOID, -1, 0);
  1562. TupleDescInitEntry(tupdesc, (AttrNumber) 4, "is_grantable",
  1563. BOOLOID, -1, 0);
  1564. funcctx->tuple_desc = BlessTupleDesc(tupdesc);
  1565. /* allocate memory for user context */
  1566. idx = (int *) palloc(sizeof(int[2]));
  1567. idx[0] = 0; /* ACL array item index */
  1568. idx[1] = -1; /* privilege type counter */
  1569. funcctx->user_fctx = (void *) idx;
  1570. MemoryContextSwitchTo(oldcontext);
  1571. }
  1572. funcctx = SRF_PERCALL_SETUP();
  1573. idx = (int *) funcctx->user_fctx;
  1574. aidat = ACL_DAT(acl);
  1575. /* need test here in case acl has no items */
  1576. while (idx[0] < ACL_NUM(acl))
  1577. {
  1578. AclItem *aidata;
  1579. AclMode priv_bit;
  1580. idx[1]++;
  1581. if (idx[1] == N_ACL_RIGHTS)
  1582. {
  1583. idx[1] = 0;
  1584. idx[0]++;
  1585. if (idx[0] >= ACL_NUM(acl)) /* done */
  1586. break;
  1587. }
  1588. aidata = &aidat[idx[0]];
  1589. priv_bit = 1 << idx[1];
  1590. if (ACLITEM_GET_PRIVS(*aidata) & priv_bit)
  1591. {
  1592. Datum result;
  1593. Datum values[4];
  1594. bool nulls[4];
  1595. HeapTuple tuple;
  1596. values[0] = ObjectIdGetDatum(aidata->ai_grantor);
  1597. values[1] = ObjectIdGetDatum(aidata->ai_grantee);
  1598. values[2] = CStringGetTextDatum(convert_aclright_to_string(priv_bit));
  1599. values[3] = BoolGetDatum((ACLITEM_GET_GOPTIONS(*aidata) & priv_bit) != 0);
  1600. MemSet(nulls, 0, sizeof(nulls));
  1601. tuple = heap_form_tuple(funcctx->tuple_desc, values, nulls);
  1602. result = HeapTupleGetDatum(tuple);
  1603. SRF_RETURN_NEXT(funcctx, result);
  1604. }
  1605. }
  1606. SRF_RETURN_DONE(funcctx);
  1607. }
  1608. /*
  1609. * has_table_privilege variants
  1610. * These are all named "has_table_privilege" at the SQL level.
  1611. * They take various combinations of relation name, relation OID,
  1612. * user name, user OID, or implicit user = current_user.
  1613. *
  1614. * The result is a boolean value: true if user has the indicated
  1615. * privilege, false if not. The variants that take a relation OID
  1616. * return NULL if the OID doesn't exist (rather than failing, as
  1617. * they did before Postgres 8.4).
  1618. */
  1619. /*
  1620. * has_table_privilege_name_name
  1621. * Check user privileges on a table given
  1622. * name username, text tablename, and text priv name.
  1623. */
  1624. Datum
  1625. has_table_privilege_name_name(PG_FUNCTION_ARGS)
  1626. {
  1627. Name rolename = PG_GETARG_NAME(0);
  1628. text *tablename = PG_GETARG_TEXT_PP(1);
  1629. text *priv_type_text = PG_GETARG_TEXT_PP(2);
  1630. Oid roleid;
  1631. Oid tableoid;
  1632. AclMode mode;
  1633. AclResult aclresult;
  1634. roleid = get_role_oid_or_public(NameStr(*rolename));
  1635. tableoid = convert_table_name(tablename);
  1636. mode = convert_table_priv_string(priv_type_text);
  1637. aclresult = pg_class_aclcheck(tableoid, roleid, mode);
  1638. PG_RETURN_BOOL(aclresult == ACLCHECK_OK);
  1639. }
  1640. /*
  1641. * has_table_privilege_name
  1642. * Check user privileges on a table given
  1643. * text tablename and text priv name.
  1644. * current_user is assumed
  1645. */
  1646. Datum
  1647. has_table_privilege_name(PG_FUNCTION_ARGS)
  1648. {
  1649. text *tablename = PG_GETARG_TEXT_PP(0);
  1650. text *priv_type_text = PG_GETARG_TEXT_PP(1);
  1651. Oid roleid;
  1652. Oid tableoid;
  1653. AclMode mode;
  1654. AclResult aclresult;
  1655. roleid = GetUserId();
  1656. tableoid = convert_table_name(tablename);
  1657. mode = convert_table_priv_string(priv_type_text);
  1658. aclresult = pg_class_aclcheck(tableoid, roleid, mode);
  1659. PG_RETURN_BOOL(aclresult == ACLCHECK_OK);
  1660. }
  1661. /*
  1662. * has_table_privilege_name_id
  1663. * Check user privileges on a table given
  1664. * name usename, table oid, and text priv name.
  1665. */
  1666. Datum
  1667. has_table_privilege_name_id(PG_FUNCTION_ARGS)
  1668. {
  1669. Name username = PG_GETARG_NAME(0);
  1670. Oid tableoid = PG_GETARG_OID(1);
  1671. text *priv_type_text = PG_GETARG_TEXT_PP(2);
  1672. Oid roleid;
  1673. AclMode mode;
  1674. AclResult aclresult;
  1675. roleid = get_role_oid_or_public(NameStr(*username));
  1676. mode = convert_table_priv_string(priv_type_text);
  1677. if (!SearchSysCacheExists1(RELOID, ObjectIdGetDatum(tableoid)))
  1678. PG_RETURN_NULL();
  1679. aclresult = pg_class_aclcheck(tableoid, roleid, mode);
  1680. PG_RETURN_BOOL(aclresult == ACLCHECK_OK);
  1681. }
  1682. /*
  1683. * has_table_privilege_id
  1684. * Check user privileges on a table given
  1685. * table oid, and text priv name.
  1686. * current_user is assumed
  1687. */
  1688. Datum
  1689. has_table_privilege_id(PG_FUNCTION_ARGS)
  1690. {
  1691. Oid tableoid = PG_GETARG_OID(0);
  1692. text *priv_type_text = PG_GETARG_TEXT_PP(1);
  1693. Oid roleid;
  1694. AclMode mode;
  1695. AclResult aclresult;
  1696. roleid = GetUserId();
  1697. mode = convert_table_priv_string(priv_type_text);
  1698. if (!SearchSysCacheExists1(RELOID, ObjectIdGetDatum(tableoid)))
  1699. PG_RETURN_NULL();
  1700. aclresult = pg_class_aclcheck(tableoid, roleid, mode);
  1701. PG_RETURN_BOOL(aclresult == ACLCHECK_OK);
  1702. }
  1703. /*
  1704. * has_table_privilege_id_name
  1705. * Check user privileges on a table given
  1706. * roleid, text tablename, and text priv name.
  1707. */
  1708. Datum
  1709. has_table_privilege_id_name(PG_FUNCTION_ARGS)
  1710. {
  1711. Oid roleid = PG_GETARG_OID(0);
  1712. text *tablename = PG_GETARG_TEXT_PP(1);
  1713. text *priv_type_text = PG_GETARG_TEXT_PP(2);
  1714. Oid tableoid;
  1715. AclMode mode;
  1716. AclResult aclresult;
  1717. tableoid = convert_table_name(tablename);
  1718. mode = convert_table_priv_string(priv_type_text);
  1719. aclresult = pg_class_aclcheck(tableoid, roleid, mode);
  1720. PG_RETURN_BOOL(aclresult == ACLCHECK_OK);
  1721. }
  1722. /*
  1723. * has_table_privilege_id_id
  1724. * Check user privileges on a table given
  1725. * roleid, table oid, and text priv name.
  1726. */
  1727. Datum
  1728. has_table_privilege_id_id(PG_FUNCTION_ARGS)
  1729. {
  1730. Oid roleid = PG_GETARG_OID(0);
  1731. Oid tableoid = PG_GETARG_OID(1);
  1732. text *priv_type_text = PG_GETARG_TEXT_PP(2);
  1733. AclMode mode;
  1734. AclResult aclresult;
  1735. mode = convert_table_priv_string(priv_type_text);
  1736. if (!SearchSysCacheExists1(RELOID, ObjectIdGetDatum(tableoid)))
  1737. PG_RETURN_NULL();
  1738. aclresult = pg_class_aclcheck(tableoid, roleid, mode);
  1739. PG_RETURN_BOOL(aclresult == ACLCHECK_OK);
  1740. }
  1741. /*
  1742. * Support routines for has_table_privilege family.
  1743. */
  1744. /*
  1745. * Given a table name expressed as a string, look it up and return Oid
  1746. */
  1747. static Oid
  1748. convert_table_name(text *tablename)
  1749. {
  1750. RangeVar *relrv;
  1751. relrv = makeRangeVarFromNameList(textToQualifiedNameList(tablename));
  1752. /* We might not even have permissions on this relation; don't lock it. */
  1753. return RangeVarGetRelid(relrv, NoLock, false);
  1754. }
  1755. /*
  1756. * convert_table_priv_string
  1757. * Convert text string to AclMode value.
  1758. */
  1759. static AclMode
  1760. convert_table_priv_string(text *priv_type_text)
  1761. {
  1762. static const priv_map table_priv_map[] = {
  1763. {"SELECT", ACL_SELECT},
  1764. {"SELECT WITH GRANT OPTION", ACL_GRANT_OPTION_FOR(ACL_SELECT)},
  1765. {"INSERT", ACL_INSERT},
  1766. {"INSERT WITH GRANT OPTION", ACL_GRANT_OPTION_FOR(ACL_INSERT)},
  1767. {"UPDATE", ACL_UPDATE},
  1768. {"UPDATE WITH GRANT OPTION", ACL_GRANT_OPTION_FOR(ACL_UPDATE)},
  1769. {"DELETE", ACL_DELETE},
  1770. {"DELETE WITH GRANT OPTION", ACL_GRANT_OPTION_FOR(ACL_DELETE)},
  1771. {"TRUNCATE", ACL_TRUNCATE},
  1772. {"TRUNCATE WITH GRANT OPTION", ACL_GRANT_OPTION_FOR(ACL_TRUNCATE)},
  1773. {"REFERENCES", ACL_REFERENCES},
  1774. {"REFERENCES WITH GRANT OPTION", ACL_GRANT_OPTION_FOR(ACL_REFERENCES)},
  1775. {"TRIGGER", ACL_TRIGGER},
  1776. {"TRIGGER WITH GRANT OPTION", ACL_GRANT_OPTION_FOR(ACL_TRIGGER)},
  1777. {"RULE", 0}, /* ignore old RULE privileges */
  1778. {"RULE WITH GRANT OPTION", 0},
  1779. {NULL, 0}
  1780. };
  1781. return convert_any_priv_string(priv_type_text, table_priv_map);
  1782. }
  1783. /*
  1784. * has_sequence_privilege variants
  1785. * These are all named "has_sequence_privilege" at the SQL level.
  1786. * They take various combinations of relation name, relation OID,
  1787. * user name, user OID, or implicit user = current_user.
  1788. *
  1789. * The result is a boolean value: true if user has the indicated
  1790. * privilege, false if not. The variants that take a relation OID
  1791. * return NULL if the OID doesn't exist.
  1792. */
  1793. /*
  1794. * has_sequence_privilege_name_name
  1795. * Check user privileges on a sequence given
  1796. * name username, text sequencename, and text priv name.
  1797. */
  1798. Datum
  1799. has_sequence_privilege_name_name(PG_FUNCTION_ARGS)
  1800. {
  1801. Name rolename = PG_GETARG_NAME(0);
  1802. text *sequencename = PG_GETARG_TEXT_PP(1);
  1803. text *priv_type_text = PG_GETARG_TEXT_PP(2);
  1804. Oid roleid;
  1805. Oid sequenceoid;
  1806. AclMode mode;
  1807. AclResult aclresult;
  1808. roleid = get_role_oid_or_public(NameStr(*rolename));
  1809. mode = convert_sequence_priv_string(priv_type_text);
  1810. sequenceoid = convert_table_name(sequencename);
  1811. if (get_rel_relkind(sequenceoid) != RELKIND_SEQUENCE)
  1812. ereport(ERROR,
  1813. (errcode(ERRCODE_WRONG_OBJECT_TYPE),
  1814. errmsg("\"%s\" is not a sequence",
  1815. text_to_cstring(sequencename))));
  1816. aclresult = pg_class_aclcheck(sequenceoid, roleid, mode);
  1817. PG_RETURN_BOOL(aclresult == ACLCHECK_OK);
  1818. }
  1819. /*
  1820. * has_sequence_privilege_name
  1821. * Check user privileges on a sequence given
  1822. * text sequencename and text priv name.
  1823. * current_user is assumed
  1824. */
  1825. Datum
  1826. has_sequence_privilege_name(PG_FUNCTION_ARGS)
  1827. {
  1828. text *sequencename = PG_GETARG_TEXT_PP(0);
  1829. text *priv_type_text = PG_GETARG_TEXT_PP(1);
  1830. Oid roleid;
  1831. Oid sequenceoid;
  1832. AclMode mode;
  1833. AclResult aclresult;
  1834. roleid = GetUserId();
  1835. mode = convert_sequence_priv_string(priv_type_text);
  1836. sequenceoid = convert_table_name(sequencename);
  1837. if (get_rel_relkind(sequenceoid) != RELKIND_SEQUENCE)
  1838. ereport(ERROR,
  1839. (errcode(ERRCODE_WRONG_OBJECT_TYPE),
  1840. errmsg("\"%s\" is not a sequence",
  1841. text_to_cstring(sequencename))));
  1842. aclresult = pg_class_aclcheck(sequenceoid, roleid, mode);
  1843. PG_RETURN_BOOL(aclresult == ACLCHECK_OK);
  1844. }
  1845. /*
  1846. * has_sequence_privilege_name_id
  1847. * Check user privileges on a sequence given
  1848. * name usename, sequence oid, and text priv name.
  1849. */
  1850. Datum
  1851. has_sequence_privilege_name_id(PG_FUNCTION_ARGS)
  1852. {
  1853. Name username = PG_GETARG_NAME(0);
  1854. Oid sequenceoid = PG_GETARG_OID(1);
  1855. text *priv_type_text = PG_GETARG_TEXT_PP(2);
  1856. Oid roleid;
  1857. AclMode mode;
  1858. AclResult aclresult;
  1859. char relkind;
  1860. roleid = get_role_oid_or_public(NameStr(*username));
  1861. mode = convert_sequence_priv_string(priv_type_text);
  1862. relkind = get_rel_relkind(sequenceoid);
  1863. if (relkind == '\0')
  1864. PG_RETURN_NULL();
  1865. else if (relkind != RELKIND_SEQUENCE)
  1866. ereport(ERROR,
  1867. (errcode(ERRCODE_WRONG_OBJECT_TYPE),
  1868. errmsg("\"%s\" is not a sequence",
  1869. get_rel_name(sequenceoid))));
  1870. aclresult = pg_class_aclcheck(sequenceoid, roleid, mode);
  1871. PG_RETURN_BOOL(aclresult == ACLCHECK_OK);
  1872. }
  1873. /*
  1874. * has_sequence_privilege_id
  1875. * Check user privileges on a sequence given
  1876. * sequence oid, and text priv name.
  1877. * current_user is assumed
  1878. */
  1879. Datum
  1880. has_sequence_privilege_id(PG_FUNCTION_ARGS)
  1881. {
  1882. Oid sequenceoid = PG_GETARG_OID(0);
  1883. text *priv_type_text = PG_GETARG_TEXT_PP(1);
  1884. Oid roleid;
  1885. AclMode mode;
  1886. AclResult aclresult;
  1887. char relkind;
  1888. roleid = GetUserId();
  1889. mode = convert_sequence_priv_string(priv_type_text);
  1890. relkind = get_rel_relkind(sequenceoid);
  1891. if (relkind == '\0')
  1892. PG_RETURN_NULL();
  1893. else if (relkind != RELKIND_SEQUENCE)
  1894. ereport(ERROR,
  1895. (errcode(ERRCODE_WRONG_OBJECT_TYPE),
  1896. errmsg("\"%s\" is not a sequence",
  1897. get_rel_name(sequenceoid))));
  1898. aclresult = pg_class_aclcheck(sequenceoid, roleid, mode);
  1899. PG_RETURN_BOOL(aclresult == ACLCHECK_OK);
  1900. }
  1901. /*
  1902. * has_sequence_privilege_id_name
  1903. * Check user privileges on a sequence given
  1904. * roleid, text sequencename, and text priv name.
  1905. */
  1906. Datum
  1907. has_sequence_privilege_id_name(PG_FUNCTION_ARGS)
  1908. {
  1909. Oid roleid = PG_GETARG_OID(0);
  1910. text *sequencename = PG_GETARG_TEXT_PP(1);
  1911. text *priv_type_text = PG_GETARG_TEXT_PP(2);
  1912. Oid sequenceoid;
  1913. AclMode mode;
  1914. AclResult aclresult;
  1915. mode = convert_sequence_priv_string(priv_type_text);
  1916. sequenceoid = convert_table_name(sequencename);
  1917. if (get_rel_relkind(sequenceoid) != RELKIND_SEQUENCE)
  1918. ereport(ERROR,
  1919. (errcode(ERRCODE_WRONG_OBJECT_TYPE),
  1920. errmsg("\"%s\" is not a sequence",
  1921. text_to_cstring(sequencename))));
  1922. aclresult = pg_class_aclcheck(sequenceoid, roleid, mode);
  1923. PG_RETURN_BOOL(aclresult == ACLCHECK_OK);
  1924. }
  1925. /*
  1926. * has_sequence_privilege_id_id
  1927. * Check user privileges on a sequence given
  1928. * roleid, sequence oid, and text priv name.
  1929. */
  1930. Datum
  1931. has_sequence_privilege_id_id(PG_FUNCTION_ARGS)
  1932. {
  1933. Oid roleid = PG_GETARG_OID(0);
  1934. Oid sequenceoid = PG_GETARG_OID(1);
  1935. text *priv_type_text = PG_GETARG_TEXT_PP(2);
  1936. AclMode mode;
  1937. AclResult aclresult;
  1938. char relkind;
  1939. mode = convert_sequence_priv_string(priv_type_text);
  1940. relkind = get_rel_relkind(sequenceoid);
  1941. if (relkind == '\0')
  1942. PG_RETURN_NULL();
  1943. else if (relkind != RELKIND_SEQUENCE)
  1944. ereport(ERROR,
  1945. (errcode(ERRCODE_WRONG_OBJECT_TYPE),
  1946. errmsg("\"%s\" is not a sequence",
  1947. get_rel_name(sequenceoid))));
  1948. aclresult = pg_class_aclcheck(sequenceoid, roleid, mode);
  1949. PG_RETURN_BOOL(aclresult == ACLCHECK_OK);
  1950. }
  1951. /*
  1952. * convert_sequence_priv_string
  1953. * Convert text string to AclMode value.
  1954. */
  1955. static AclMode
  1956. convert_sequence_priv_string(text *priv_type_text)
  1957. {
  1958. static const priv_map sequence_priv_map[] = {
  1959. {"USAGE", ACL_USAGE},
  1960. {"USAGE WITH GRANT OPTION", ACL_GRANT_OPTION_FOR(ACL_USAGE)},
  1961. {"SELECT", ACL_SELECT},
  1962. {"SELECT WITH GRANT OPTION", ACL_GRANT_OPTION_FOR(ACL_SELECT)},
  1963. {"UPDATE", ACL_UPDATE},
  1964. {"UPDATE WITH GRANT OPTION", ACL_GRANT_OPTION_FOR(ACL_UPDATE)},
  1965. {NULL, 0}
  1966. };
  1967. return convert_any_priv_string(priv_type_text, sequence_priv_map);
  1968. }
  1969. /*
  1970. * has_any_column_privilege variants
  1971. * These are all named "has_any_column_privilege" at the SQL level.
  1972. * They take various combinations of relation name, relation OID,
  1973. * user name, user OID, or implicit user = current_user.
  1974. *
  1975. * The result is a boolean value: true if user has the indicated
  1976. * privilege for any column of the table, false if not. The variants
  1977. * that take a relation OID return NULL if the OID doesn't exist.
  1978. */
  1979. /*
  1980. * has_any_column_privilege_name_name
  1981. * Check user privileges on any column of a table given
  1982. * name username, text tablename, and text priv name.
  1983. */
  1984. Datum
  1985. has_any_column_privilege_name_name(PG_FUNCTION_ARGS)
  1986. {
  1987. Name rolename = PG_GETARG_NAME(0);
  1988. text *tablename = PG_GETARG_TEXT_PP(1);
  1989. text *priv_type_text = PG_GETARG_TEXT_PP(2);
  1990. Oid roleid;
  1991. Oid tableoid;
  1992. AclMode mode;
  1993. AclResult aclresult;
  1994. roleid = get_role_oid_or_public(NameStr(*rolename));
  1995. tableoid = convert_table_name(tablename);
  1996. mode = convert_column_priv_string(priv_type_text);
  1997. /* First check at table level, then examine each column if needed */
  1998. aclresult = pg_class_aclcheck(tableoid, roleid, mode);
  1999. if (aclresult != ACLCHECK_OK)
  2000. aclresult = pg_attribute_aclcheck_all(tableoid, roleid, mode,
  2001. ACLMASK_ANY);
  2002. PG_RETURN_BOOL(aclresult == ACLCHECK_OK);
  2003. }
  2004. /*
  2005. * has_any_column_privilege_name
  2006. * Check user privileges on any column of a table given
  2007. * text tablename and text priv name.
  2008. * current_user is assumed
  2009. */
  2010. Datum
  2011. has_any_column_privilege_name(PG_FUNCTION_ARGS)
  2012. {
  2013. text *tablename = PG_GETARG_TEXT_PP(0);
  2014. text *priv_type_text = PG_GETARG_TEXT_PP(1);
  2015. Oid roleid;
  2016. Oid tableoid;
  2017. AclMode mode;
  2018. AclResult aclresult;
  2019. roleid = GetUserId();
  2020. tableoid = convert_table_name(tablename);
  2021. mode = convert_column_priv_string(priv_type_text);
  2022. /* First check at table level, then examine each column if needed */
  2023. aclresult = pg_class_aclcheck(tableoid, roleid, mode);
  2024. if (aclresult != ACLCHECK_OK)
  2025. aclresult = pg_attribute_aclcheck_all(tableoid, roleid, mode,
  2026. ACLMASK_ANY);
  2027. PG_RETURN_BOOL(aclresult == ACLCHECK_OK);
  2028. }
  2029. /*
  2030. * has_any_column_privilege_name_id
  2031. * Check user privileges on any column of a table given
  2032. * name usename, table oid, and text priv name.
  2033. */
  2034. Datum
  2035. has_any_column_privilege_name_id(PG_FUNCTION_ARGS)
  2036. {
  2037. Name username = PG_GETARG_NAME(0);
  2038. Oid tableoid = PG_GETARG_OID(1);
  2039. text *priv_type_text = PG_GETARG_TEXT_PP(2);
  2040. Oid roleid;
  2041. AclMode mode;
  2042. AclResult aclresult;
  2043. roleid = get_role_oid_or_public(NameStr(*username));
  2044. mode = convert_column_priv_string(priv_type_text);
  2045. if (!SearchSysCacheExists1(RELOID, ObjectIdGetDatum(tableoid)))
  2046. PG_RETURN_NULL();
  2047. /* First check at table level, then examine each column if needed */
  2048. aclresult = pg_class_aclcheck(tableoid, roleid, mode);
  2049. if (aclresult != ACLCHECK_OK)
  2050. aclresult = pg_attribute_aclcheck_all(tableoid, roleid, mode,
  2051. ACLMASK_ANY);
  2052. PG_RETURN_BOOL(aclresult == ACLCHECK_OK);
  2053. }
  2054. /*
  2055. * has_any_column_privilege_id
  2056. * Check user privileges on any column of a table given
  2057. * table oid, and text priv name.
  2058. * current_user is assumed
  2059. */
  2060. Datum
  2061. has_any_column_privilege_id(PG_FUNCTION_ARGS)
  2062. {
  2063. Oid tableoid = PG_GETARG_OID(0);
  2064. text *priv_type_text = PG_GETARG_TEXT_PP(1);
  2065. Oid roleid;
  2066. AclMode mode;
  2067. AclResult aclresult;
  2068. roleid = GetUserId();
  2069. mode = convert_column_priv_string(priv_type_text);
  2070. if (!SearchSysCacheExists1(RELOID, ObjectIdGetDatum(tableoid)))
  2071. PG_RETURN_NULL();
  2072. /* First check at table level, then examine each column if needed */
  2073. aclresult = pg_class_aclcheck(tableoid, roleid, mode);
  2074. if (aclresult != ACLCHECK_OK)
  2075. aclresult = pg_attribute_aclcheck_all(tableoid, roleid, mode,
  2076. ACLMASK_ANY);
  2077. PG_RETURN_BOOL(aclresult == ACLCHECK_OK);
  2078. }
  2079. /*
  2080. * has_any_column_privilege_id_name
  2081. * Check user privileges on any column of a table given
  2082. * roleid, text tablename, and text priv name.
  2083. */
  2084. Datum
  2085. has_any_column_privilege_id_name(PG_FUNCTION_ARGS)
  2086. {
  2087. Oid roleid = PG_GETARG_OID(0);
  2088. text *tablename = PG_GETARG_TEXT_PP(1);
  2089. text *priv_type_text = PG_GETARG_TEXT_PP(2);
  2090. Oid tableoid;
  2091. AclMode mode;
  2092. AclResult aclresult;
  2093. tableoid = convert_table_name(tablename);
  2094. mode = convert_column_priv_string(priv_type_text);
  2095. /* First check at table level, then examine each column if needed */
  2096. aclresult = pg_class_aclcheck(tableoid, roleid, mode);
  2097. if (aclresult != ACLCHECK_OK)
  2098. aclresult = pg_attribute_aclcheck_all(tableoid, roleid, mode,
  2099. ACLMASK_ANY);
  2100. PG_RETURN_BOOL(aclresult == ACLCHECK_OK);
  2101. }
  2102. /*
  2103. * has_any_column_privilege_id_id
  2104. * Check user privileges on any column of a table given
  2105. * roleid, table oid, and text priv name.
  2106. */
  2107. Datum
  2108. has_any_column_privilege_id_id(PG_FUNCTION_ARGS)
  2109. {
  2110. Oid roleid = PG_GETARG_OID(0);
  2111. Oid tableoid = PG_GETARG_OID(1);
  2112. text *priv_type_text = PG_GETARG_TEXT_PP(2);
  2113. AclMode mode;
  2114. AclResult aclresult;
  2115. mode = convert_column_priv_string(priv_type_text);
  2116. if (!SearchSysCacheExists1(RELOID, ObjectIdGetDatum(tableoid)))
  2117. PG_RETURN_NULL();
  2118. /* First check at table level, then examine each column if needed */
  2119. aclresult = pg_class_aclcheck(tableoid, roleid, mode);
  2120. if (aclresult != ACLCHECK_OK)
  2121. aclresult = pg_attribute_aclcheck_all(tableoid, roleid, mode,
  2122. ACLMASK_ANY);
  2123. PG_RETURN_BOOL(aclresult == ACLCHECK_OK);
  2124. }
  2125. /*
  2126. * has_column_privilege variants
  2127. * These are all named "has_column_privilege" at the SQL level.
  2128. * They take various combinations of relation name, relation OID,
  2129. * column name, column attnum, user name, user OID, or
  2130. * implicit user = current_user.
  2131. *
  2132. * The result is a boolean value: true if user has the indicated
  2133. * privilege, false if not. The variants that take a relation OID
  2134. * return NULL (rather than throwing an error) if that relation OID
  2135. * doesn't exist. Likewise, the variants that take an integer attnum
  2136. * return NULL (rather than throwing an error) if there is no such
  2137. * pg_attribute entry. All variants return NULL if an attisdropped
  2138. * column is selected. These rules are meant to avoid unnecessary
  2139. * failures in queries that scan pg_attribute.
  2140. */
  2141. /*
  2142. * column_privilege_check: check column privileges, but don't throw an error
  2143. * for dropped column or table
  2144. *
  2145. * Returns 1 if have the privilege, 0 if not, -1 if dropped column/table.
  2146. */
  2147. static int
  2148. column_privilege_check(Oid tableoid, AttrNumber attnum,
  2149. Oid roleid, AclMode mode)
  2150. {
  2151. AclResult aclresult;
  2152. HeapTuple attTuple;
  2153. Form_pg_attribute attributeForm;
  2154. /*
  2155. * If convert_column_name failed, we can just return -1 immediately.
  2156. */
  2157. if (attnum == InvalidAttrNumber)
  2158. return -1;
  2159. /*
  2160. * First check if we have the privilege at the table level. We check
  2161. * existence of the pg_class row before risking calling pg_class_aclcheck.
  2162. * Note: it might seem there's a race condition against concurrent DROP,
  2163. * but really it's safe because there will be no syscache flush between
  2164. * here and there. So if we see the row in the syscache, so will
  2165. * pg_class_aclcheck.
  2166. */
  2167. if (!SearchSysCacheExists1(RELOID, ObjectIdGetDatum(tableoid)))
  2168. return -1;
  2169. aclresult = pg_class_aclcheck(tableoid, roleid, mode);
  2170. if (aclresult == ACLCHECK_OK)
  2171. return true;
  2172. /*
  2173. * No table privilege, so try per-column privileges. Again, we have to
  2174. * check for dropped attribute first, and we rely on the syscache not to
  2175. * notice a concurrent drop before pg_attribute_aclcheck fetches the row.
  2176. */
  2177. attTuple = SearchSysCache2(ATTNUM,
  2178. ObjectIdGetDatum(tableoid),
  2179. Int16GetDatum(attnum));
  2180. if (!HeapTupleIsValid(attTuple))
  2181. return -1;
  2182. attributeForm = (Form_pg_attribute) GETSTRUCT(attTuple);
  2183. if (attributeForm->attisdropped)
  2184. {
  2185. ReleaseSysCache(attTuple);
  2186. return -1;
  2187. }
  2188. ReleaseSysCache(attTuple);
  2189. aclresult = pg_attribute_aclcheck(tableoid, attnum, roleid, mode);
  2190. return (aclresult == ACLCHECK_OK);
  2191. }
  2192. /*
  2193. * has_column_privilege_name_name_name
  2194. * Check user privileges on a column given
  2195. * name username, text tablename, text colname, and text priv name.
  2196. */
  2197. Datum
  2198. has_column_privilege_name_name_name(PG_FUNCTION_ARGS)
  2199. {
  2200. Name rolename = PG_GETARG_NAME(0);
  2201. text *tablename = PG_GETARG_TEXT_PP(1);
  2202. text *column = PG_GETARG_TEXT_PP(2);
  2203. text *priv_type_text = PG_GETARG_TEXT_PP(3);
  2204. Oid roleid;
  2205. Oid tableoid;
  2206. AttrNumber colattnum;
  2207. AclMode mode;
  2208. int privresult;
  2209. roleid = get_role_oid_or_public(NameStr(*rolename));
  2210. tableoid = convert_table_name(tablename);
  2211. colattnum = convert_column_name(tableoid, column);
  2212. mode = convert_column_priv_string(priv_type_text);
  2213. privresult = column_privilege_check(tableoid, colattnum, roleid, mode);
  2214. if (privresult < 0)
  2215. PG_RETURN_NULL();
  2216. PG_RETURN_BOOL(privresult);
  2217. }
  2218. /*
  2219. * has_column_privilege_name_name_attnum
  2220. * Check user privileges on a column given
  2221. * name username, text tablename, int attnum, and text priv name.
  2222. */
  2223. Datum
  2224. has_column_privilege_name_name_attnum(PG_FUNCTION_ARGS)
  2225. {
  2226. Name rolename = PG_GETARG_NAME(0);
  2227. text *tablename = PG_GETARG_TEXT_PP(1);
  2228. AttrNumber colattnum = PG_GETARG_INT16(2);
  2229. text *priv_type_text = PG_GETARG_TEXT_PP(3);
  2230. Oid roleid;
  2231. Oid tableoid;
  2232. AclMode mode;
  2233. int privresult;
  2234. roleid = get_role_oid_or_public(NameStr(*rolename));
  2235. tableoid = convert_table_name(tablename);
  2236. mode = convert_column_priv_string(priv_type_text);
  2237. privresult = column_privilege_check(tableoid, colattnum, roleid, mode);
  2238. if (privresult < 0)
  2239. PG_RETURN_NULL();
  2240. PG_RETURN_BOOL(privresult);
  2241. }
  2242. /*
  2243. * has_column_privilege_name_id_name
  2244. * Check user privileges on a column given
  2245. * name username, table oid, text colname, and text priv name.
  2246. */
  2247. Datum
  2248. has_column_privilege_name_id_name(PG_FUNCTION_ARGS)
  2249. {
  2250. Name username = PG_GETARG_NAME(0);
  2251. Oid tableoid = PG_GETARG_OID(1);
  2252. text *column = PG_GETARG_TEXT_PP(2);
  2253. text *priv_type_text = PG_GETARG_TEXT_PP(3);
  2254. Oid roleid;
  2255. AttrNumber colattnum;
  2256. AclMode mode;
  2257. int privresult;
  2258. roleid = get_role_oid_or_public(NameStr(*username));
  2259. colattnum = convert_column_name(tableoid, column);
  2260. mode = convert_column_priv_string(priv_type_text);
  2261. privresult = column_privilege_check(tableoid, colattnum, roleid, mode);
  2262. if (privresult < 0)
  2263. PG_RETURN_NULL();
  2264. PG_RETURN_BOOL(privresult);
  2265. }
  2266. /*
  2267. * has_column_privilege_name_id_attnum
  2268. * Check user privileges on a column given
  2269. * name username, table oid, int attnum, and text priv name.
  2270. */
  2271. Datum
  2272. has_column_privilege_name_id_attnum(PG_FUNCTION_ARGS)
  2273. {
  2274. Name username = PG_GETARG_NAME(0);
  2275. Oid tableoid = PG_GETARG_OID(1);
  2276. AttrNumber colattnum = PG_GETARG_INT16(2);
  2277. text *priv_type_text = PG_GETARG_TEXT_PP(3);
  2278. Oid roleid;
  2279. AclMode mode;
  2280. int privresult;
  2281. roleid = get_role_oid_or_public(NameStr(*username));
  2282. mode = convert_column_priv_string(priv_type_text);
  2283. privresult = column_privilege_check(tableoid, colattnum, roleid, mode);
  2284. if (privresult < 0)
  2285. PG_RETURN_NULL();
  2286. PG_RETURN_BOOL(privresult);
  2287. }
  2288. /*
  2289. * has_column_privilege_id_name_name
  2290. * Check user privileges on a column given
  2291. * oid roleid, text tablename, text colname, and text priv name.
  2292. */
  2293. Datum
  2294. has_column_privilege_id_name_name(PG_FUNCTION_ARGS)
  2295. {
  2296. Oid roleid = PG_GETARG_OID(0);
  2297. text *tablename = PG_GETARG_TEXT_PP(1);
  2298. text *column = PG_GETARG_TEXT_PP(2);
  2299. text *priv_type_text = PG_GETARG_TEXT_PP(3);
  2300. Oid tableoid;
  2301. AttrNumber colattnum;
  2302. AclMode mode;
  2303. int privresult;
  2304. tableoid = convert_table_name(tablename);
  2305. colattnum = convert_column_name(tableoid, column);
  2306. mode = convert_column_priv_string(priv_type_text);
  2307. privresult = column_privilege_check(tableoid, colattnum, roleid, mode);
  2308. if (privresult < 0)
  2309. PG_RETURN_NULL();
  2310. PG_RETURN_BOOL(privresult);
  2311. }
  2312. /*
  2313. * has_column_privilege_id_name_attnum
  2314. * Check user privileges on a column given
  2315. * oid roleid, text tablename, int attnum, and text priv name.
  2316. */
  2317. Datum
  2318. has_column_privilege_id_name_attnum(PG_FUNCTION_ARGS)
  2319. {
  2320. Oid roleid = PG_GETARG_OID(0);
  2321. text *tablename = PG_GETARG_TEXT_PP(1);
  2322. AttrNumber colattnum = PG_GETARG_INT16(2);
  2323. text *priv_type_text = PG_GETARG_TEXT_PP(3);
  2324. Oid tableoid;
  2325. AclMode mode;
  2326. int privresult;
  2327. tableoid = convert_table_name(tablename);
  2328. mode = convert_column_priv_string(priv_type_text);
  2329. privresult = column_privilege_check(tableoid, colattnum, roleid, mode);
  2330. if (privresult < 0)
  2331. PG_RETURN_NULL();
  2332. PG_RETURN_BOOL(privresult);
  2333. }
  2334. /*
  2335. * has_column_privilege_id_id_name
  2336. * Check user privileges on a column given
  2337. * oid roleid, table oid, text colname, and text priv name.
  2338. */
  2339. Datum
  2340. has_column_privilege_id_id_name(PG_FUNCTION_ARGS)
  2341. {
  2342. Oid roleid = PG_GETARG_OID(0);
  2343. Oid tableoid = PG_GETARG_OID(1);
  2344. text *column = PG_GETARG_TEXT_PP(2);
  2345. text *priv_type_text = PG_GETARG_TEXT_PP(3);
  2346. AttrNumber colattnum;
  2347. AclMode mode;
  2348. int privresult;
  2349. colattnum = convert_column_name(tableoid, column);
  2350. mode = convert_column_priv_string(priv_type_text);
  2351. privresult = column_privilege_check(tableoid, colattnum, roleid, mode);
  2352. if (privresult < 0)
  2353. PG_RETURN_NULL();
  2354. PG_RETURN_BOOL(privresult);
  2355. }
  2356. /*
  2357. * has_column_privilege_id_id_attnum
  2358. * Check user privileges on a column given
  2359. * oid roleid, table oid, int attnum, and text priv name.
  2360. */
  2361. Datum
  2362. has_column_privilege_id_id_attnum(PG_FUNCTION_ARGS)
  2363. {
  2364. Oid roleid = PG_GETARG_OID(0);
  2365. Oid tableoid = PG_GETARG_OID(1);
  2366. AttrNumber colattnum = PG_GETARG_INT16(2);
  2367. text *priv_type_text = PG_GETARG_TEXT_PP(3);
  2368. AclMode mode;
  2369. int privresult;
  2370. mode = convert_column_priv_string(priv_type_text);
  2371. privresult = column_privilege_check(tableoid, colattnum, roleid, mode);
  2372. if (privresult < 0)
  2373. PG_RETURN_NULL();
  2374. PG_RETURN_BOOL(privresult);
  2375. }
  2376. /*
  2377. * has_column_privilege_name_name
  2378. * Check user privileges on a column given
  2379. * text tablename, text colname, and text priv name.
  2380. * current_user is assumed
  2381. */
  2382. Datum
  2383. has_column_privilege_name_name(PG_FUNCTION_ARGS)
  2384. {
  2385. text *tablename = PG_GETARG_TEXT_PP(0);
  2386. text *column = PG_GETARG_TEXT_PP(1);
  2387. text *priv_type_text = PG_GETARG_TEXT_PP(2);
  2388. Oid roleid;
  2389. Oid tableoid;
  2390. AttrNumber colattnum;
  2391. AclMode mode;
  2392. int privresult;
  2393. roleid = GetUserId();
  2394. tableoid = convert_table_name(tablename);
  2395. colattnum = convert_column_name(tableoid, column);
  2396. mode = convert_column_priv_string(priv_type_text);
  2397. privresult = column_privilege_check(tableoid, colattnum, roleid, mode);
  2398. if (privresult < 0)
  2399. PG_RETURN_NULL();
  2400. PG_RETURN_BOOL(privresult);
  2401. }
  2402. /*
  2403. * has_column_privilege_name_attnum
  2404. * Check user privileges on a column given
  2405. * text tablename, int attnum, and text priv name.
  2406. * current_user is assumed
  2407. */
  2408. Datum
  2409. has_column_privilege_name_attnum(PG_FUNCTION_ARGS)
  2410. {
  2411. text *tablename = PG_GETARG_TEXT_PP(0);
  2412. AttrNumber colattnum = PG_GETARG_INT16(1);
  2413. text *priv_type_text = PG_GETARG_TEXT_PP(2);
  2414. Oid roleid;
  2415. Oid tableoid;
  2416. AclMode mode;
  2417. int privresult;
  2418. roleid = GetUserId();
  2419. tableoid = convert_table_name(tablename);
  2420. mode = convert_column_priv_string(priv_type_text);
  2421. privresult = column_privilege_check(tableoid, colattnum, roleid, mode);
  2422. if (privresult < 0)
  2423. PG_RETURN_NULL();
  2424. PG_RETURN_BOOL(privresult);
  2425. }
  2426. /*
  2427. * has_column_privilege_id_name
  2428. * Check user privileges on a column given
  2429. * table oid, text colname, and text priv name.
  2430. * current_user is assumed
  2431. */
  2432. Datum
  2433. has_column_privilege_id_name(PG_FUNCTION_ARGS)
  2434. {
  2435. Oid tableoid = PG_GETARG_OID(0);
  2436. text *column = PG_GETARG_TEXT_PP(1);
  2437. text *priv_type_text = PG_GETARG_TEXT_PP(2);
  2438. Oid roleid;
  2439. AttrNumber colattnum;
  2440. AclMode mode;
  2441. int privresult;
  2442. roleid = GetUserId();
  2443. colattnum = convert_column_name(tableoid, column);
  2444. mode = convert_column_priv_string(priv_type_text);
  2445. privresult = column_privilege_check(tableoid, colattnum, roleid, mode);
  2446. if (privresult < 0)
  2447. PG_RETURN_NULL();
  2448. PG_RETURN_BOOL(privresult);
  2449. }
  2450. /*
  2451. * has_column_privilege_id_attnum
  2452. * Check user privileges on a column given
  2453. * table oid, int attnum, and text priv name.
  2454. * current_user is assumed
  2455. */
  2456. Datum
  2457. has_column_privilege_id_attnum(PG_FUNCTION_ARGS)
  2458. {
  2459. Oid tableoid = PG_GETARG_OID(0);
  2460. AttrNumber colattnum = PG_GETARG_INT16(1);
  2461. text *priv_type_text = PG_GETARG_TEXT_PP(2);
  2462. Oid roleid;
  2463. AclMode mode;
  2464. int privresult;
  2465. roleid = GetUserId();
  2466. mode = convert_column_priv_string(priv_type_text);
  2467. privresult = column_privilege_check(tableoid, colattnum, roleid, mode);
  2468. if (privresult < 0)
  2469. PG_RETURN_NULL();
  2470. PG_RETURN_BOOL(privresult);
  2471. }
  2472. /*
  2473. * Support routines for has_column_privilege family.
  2474. */
  2475. /*
  2476. * Given a table OID and a column name expressed as a string, look it up
  2477. * and return the column number. Returns InvalidAttrNumber in cases
  2478. * where caller should return NULL instead of failing.
  2479. */
  2480. static AttrNumber
  2481. convert_column_name(Oid tableoid, text *column)
  2482. {
  2483. char *colname;
  2484. HeapTuple attTuple;
  2485. AttrNumber attnum;
  2486. colname = text_to_cstring(column);
  2487. /*
  2488. * We don't use get_attnum() here because it will report that dropped
  2489. * columns don't exist. We need to treat dropped columns differently from
  2490. * nonexistent columns.
  2491. */
  2492. attTuple = SearchSysCache2(ATTNAME,
  2493. ObjectIdGetDatum(tableoid),
  2494. CStringGetDatum(colname));
  2495. if (HeapTupleIsValid(attTuple))
  2496. {
  2497. Form_pg_attribute attributeForm;
  2498. attributeForm = (Form_pg_attribute) GETSTRUCT(attTuple);
  2499. /* We want to return NULL for dropped columns */
  2500. if (attributeForm->attisdropped)
  2501. attnum = InvalidAttrNumber;
  2502. else
  2503. attnum = attributeForm->attnum;
  2504. ReleaseSysCache(attTuple);
  2505. }
  2506. else
  2507. {
  2508. char *tablename = get_rel_name(tableoid);
  2509. /*
  2510. * If the table OID is bogus, or it's just been dropped, we'll get
  2511. * NULL back. In such cases we want has_column_privilege to return
  2512. * NULL too, so just return InvalidAttrNumber.
  2513. */
  2514. if (tablename != NULL)
  2515. {
  2516. /* tableoid exists, colname does not, so throw error */
  2517. ereport(ERROR,
  2518. (errcode(ERRCODE_UNDEFINED_COLUMN),
  2519. errmsg("column \"%s\" of relation \"%s\" does not exist",
  2520. colname, tablename)));
  2521. }
  2522. /* tableoid doesn't exist, so act like attisdropped case */
  2523. attnum = InvalidAttrNumber;
  2524. }
  2525. pfree(colname);
  2526. return attnum;
  2527. }
  2528. /*
  2529. * convert_column_priv_string
  2530. * Convert text string to AclMode value.
  2531. */
  2532. static AclMode
  2533. convert_column_priv_string(text *priv_type_text)
  2534. {
  2535. static const priv_map column_priv_map[] = {
  2536. {"SELECT", ACL_SELECT},
  2537. {"SELECT WITH GRANT OPTION", ACL_GRANT_OPTION_FOR(ACL_SELECT)},
  2538. {"INSERT", ACL_INSERT},
  2539. {"INSERT WITH GRANT OPTION", ACL_GRANT_OPTION_FOR(ACL_INSERT)},
  2540. {"UPDATE", ACL_UPDATE},
  2541. {"UPDATE WITH GRANT OPTION", ACL_GRANT_OPTION_FOR(ACL_UPDATE)},
  2542. {"REFERENCES", ACL_REFERENCES},
  2543. {"REFERENCES WITH GRANT OPTION", ACL_GRANT_OPTION_FOR(ACL_REFERENCES)},
  2544. {NULL, 0}
  2545. };
  2546. return convert_any_priv_string(priv_type_text, column_priv_map);
  2547. }
  2548. /*
  2549. * has_database_privilege variants
  2550. * These are all named "has_database_privilege" at the SQL level.
  2551. * They take various combinations of database name, database OID,
  2552. * user name, user OID, or implicit user = current_user.
  2553. *
  2554. * The result is a boolean value: true if user has the indicated
  2555. * privilege, false if not, or NULL if object doesn't exist.
  2556. */
  2557. /*
  2558. * has_database_privilege_name_name
  2559. * Check user privileges on a database given
  2560. * name username, text databasename, and text priv name.
  2561. */
  2562. Datum
  2563. has_database_privilege_name_name(PG_FUNCTION_ARGS)
  2564. {
  2565. Name username = PG_GETARG_NAME(0);
  2566. text *databasename = PG_GETARG_TEXT_PP(1);
  2567. text *priv_type_text = PG_GETARG_TEXT_PP(2);
  2568. Oid roleid;
  2569. Oid databaseoid;
  2570. AclMode mode;
  2571. AclResult aclresult;
  2572. roleid = get_role_oid_or_public(NameStr(*username));
  2573. databaseoid = convert_database_name(databasename);
  2574. mode = convert_database_priv_string(priv_type_text);
  2575. aclresult = pg_database_aclcheck(databaseoid, roleid, mode);
  2576. PG_RETURN_BOOL(aclresult == ACLCHECK_OK);
  2577. }
  2578. /*
  2579. * has_database_privilege_name
  2580. * Check user privileges on a database given
  2581. * text databasename and text priv name.
  2582. * current_user is assumed
  2583. */
  2584. Datum
  2585. has_database_privilege_name(PG_FUNCTION_ARGS)
  2586. {
  2587. text *databasename = PG_GETARG_TEXT_PP(0);
  2588. text *priv_type_text = PG_GETARG_TEXT_PP(1);
  2589. Oid roleid;
  2590. Oid databaseoid;
  2591. AclMode mode;
  2592. AclResult aclresult;
  2593. roleid = GetUserId();
  2594. databaseoid = convert_database_name(databasename);
  2595. mode = convert_database_priv_string(priv_type_text);
  2596. aclresult = pg_database_aclcheck(databaseoid, roleid, mode);
  2597. PG_RETURN_BOOL(aclresult == ACLCHECK_OK);
  2598. }
  2599. /*
  2600. * has_database_privilege_name_id
  2601. * Check user privileges on a database given
  2602. * name usename, database oid, and text priv name.
  2603. */
  2604. Datum
  2605. has_database_privilege_name_id(PG_FUNCTION_ARGS)
  2606. {
  2607. Name username = PG_GETARG_NAME(0);
  2608. Oid databaseoid = PG_GETARG_OID(1);
  2609. text *priv_type_text = PG_GETARG_TEXT_PP(2);
  2610. Oid roleid;
  2611. AclMode mode;
  2612. AclResult aclresult;
  2613. roleid = get_role_oid_or_public(NameStr(*username));
  2614. mode = convert_database_priv_string(priv_type_text);
  2615. if (!SearchSysCacheExists1(DATABASEOID, ObjectIdGetDatum(databaseoid)))
  2616. PG_RETURN_NULL();
  2617. aclresult = pg_database_aclcheck(databaseoid, roleid, mode);
  2618. PG_RETURN_BOOL(aclresult == ACLCHECK_OK);
  2619. }
  2620. /*
  2621. * has_database_privilege_id
  2622. * Check user privileges on a database given
  2623. * database oid, and text priv name.
  2624. * current_user is assumed
  2625. */
  2626. Datum
  2627. has_database_privilege_id(PG_FUNCTION_ARGS)
  2628. {
  2629. Oid databaseoid = PG_GETARG_OID(0);
  2630. text *priv_type_text = PG_GETARG_TEXT_PP(1);
  2631. Oid roleid;
  2632. AclMode mode;
  2633. AclResult aclresult;
  2634. roleid = GetUserId();
  2635. mode = convert_database_priv_string(priv_type_text);
  2636. if (!SearchSysCacheExists1(DATABASEOID, ObjectIdGetDatum(databaseoid)))
  2637. PG_RETURN_NULL();
  2638. aclresult = pg_database_aclcheck(databaseoid, roleid, mode);
  2639. PG_RETURN_BOOL(aclresult == ACLCHECK_OK);
  2640. }
  2641. /*
  2642. * has_database_privilege_id_name
  2643. * Check user privileges on a database given
  2644. * roleid, text databasename, and text priv name.
  2645. */
  2646. Datum
  2647. has_database_privilege_id_name(PG_FUNCTION_ARGS)
  2648. {
  2649. Oid roleid = PG_GETARG_OID(0);
  2650. text *databasename = PG_GETARG_TEXT_PP(1);
  2651. text *priv_type_text = PG_GETARG_TEXT_PP(2);
  2652. Oid databaseoid;
  2653. AclMode mode;
  2654. AclResult aclresult;
  2655. databaseoid = convert_database_name(databasename);
  2656. mode = convert_database_priv_string(priv_type_text);
  2657. aclresult = pg_database_aclcheck(databaseoid, roleid, mode);
  2658. PG_RETURN_BOOL(aclresult == ACLCHECK_OK);
  2659. }
  2660. /*
  2661. * has_database_privilege_id_id
  2662. * Check user privileges on a database given
  2663. * roleid, database oid, and text priv name.
  2664. */
  2665. Datum
  2666. has_database_privilege_id_id(PG_FUNCTION_ARGS)
  2667. {
  2668. Oid roleid = PG_GETARG_OID(0);
  2669. Oid databaseoid = PG_GETARG_OID(1);
  2670. text *priv_type_text = PG_GETARG_TEXT_PP(2);
  2671. AclMode mode;
  2672. AclResult aclresult;
  2673. mode = convert_database_priv_string(priv_type_text);
  2674. if (!SearchSysCacheExists1(DATABASEOID, ObjectIdGetDatum(databaseoid)))
  2675. PG_RETURN_NULL();
  2676. aclresult = pg_database_aclcheck(databaseoid, roleid, mode);
  2677. PG_RETURN_BOOL(aclresult == ACLCHECK_OK);
  2678. }
  2679. /*
  2680. * Support routines for has_database_privilege family.
  2681. */
  2682. /*
  2683. * Given a database name expressed as a string, look it up and return Oid
  2684. */
  2685. static Oid
  2686. convert_database_name(text *databasename)
  2687. {
  2688. char *dbname = text_to_cstring(databasename);
  2689. return get_database_oid(dbname, false);
  2690. }
  2691. /*
  2692. * convert_database_priv_string
  2693. * Convert text string to AclMode value.
  2694. */
  2695. static AclMode
  2696. convert_database_priv_string(text *priv_type_text)
  2697. {
  2698. static const priv_map database_priv_map[] = {
  2699. {"CREATE", ACL_CREATE},
  2700. {"CREATE WITH GRANT OPTION", ACL_GRANT_OPTION_FOR(ACL_CREATE)},
  2701. {"TEMPORARY", ACL_CREATE_TEMP},
  2702. {"TEMPORARY WITH GRANT OPTION", ACL_GRANT_OPTION_FOR(ACL_CREATE_TEMP)},
  2703. {"TEMP", ACL_CREATE_TEMP},
  2704. {"TEMP WITH GRANT OPTION", ACL_GRANT_OPTION_FOR(ACL_CREATE_TEMP)},
  2705. {"CONNECT", ACL_CONNECT},
  2706. {"CONNECT WITH GRANT OPTION", ACL_GRANT_OPTION_FOR(ACL_CONNECT)},
  2707. {NULL, 0}
  2708. };
  2709. return convert_any_priv_string(priv_type_text, database_priv_map);
  2710. }
  2711. /*
  2712. * has_foreign_data_wrapper_privilege variants
  2713. * These are all named "has_foreign_data_wrapper_privilege" at the SQL level.
  2714. * They take various combinations of foreign-data wrapper name,
  2715. * fdw OID, user name, user OID, or implicit user = current_user.
  2716. *
  2717. * The result is a boolean value: true if user has the indicated
  2718. * privilege, false if not.
  2719. */
  2720. /*
  2721. * has_foreign_data_wrapper_privilege_name_name
  2722. * Check user privileges on a foreign-data wrapper given
  2723. * name username, text fdwname, and text priv name.
  2724. */
  2725. Datum
  2726. has_foreign_data_wrapper_privilege_name_name(PG_FUNCTION_ARGS)
  2727. {
  2728. Name username = PG_GETARG_NAME(0);
  2729. text *fdwname = PG_GETARG_TEXT_PP(1);
  2730. text *priv_type_text = PG_GETARG_TEXT_PP(2);
  2731. Oid roleid;
  2732. Oid fdwid;
  2733. AclMode mode;
  2734. AclResult aclresult;
  2735. roleid = get_role_oid_or_public(NameStr(*username));
  2736. fdwid = convert_foreign_data_wrapper_name(fdwname);
  2737. mode = convert_foreign_data_wrapper_priv_string(priv_type_text);
  2738. aclresult = pg_foreign_data_wrapper_aclcheck(fdwid, roleid, mode);
  2739. PG_RETURN_BOOL(aclresult == ACLCHECK_OK);
  2740. }
  2741. /*
  2742. * has_foreign_data_wrapper_privilege_name
  2743. * Check user privileges on a foreign-data wrapper given
  2744. * text fdwname and text priv name.
  2745. * current_user is assumed
  2746. */
  2747. Datum
  2748. has_foreign_data_wrapper_privilege_name(PG_FUNCTION_ARGS)
  2749. {
  2750. text *fdwname = PG_GETARG_TEXT_PP(0);
  2751. text *priv_type_text = PG_GETARG_TEXT_PP(1);
  2752. Oid roleid;
  2753. Oid fdwid;
  2754. AclMode mode;
  2755. AclResult aclresult;
  2756. roleid = GetUserId();
  2757. fdwid = convert_foreign_data_wrapper_name(fdwname);
  2758. mode = convert_foreign_data_wrapper_priv_string(priv_type_text);
  2759. aclresult = pg_foreign_data_wrapper_aclcheck(fdwid, roleid, mode);
  2760. PG_RETURN_BOOL(aclresult == ACLCHECK_OK);
  2761. }
  2762. /*
  2763. * has_foreign_data_wrapper_privilege_name_id
  2764. * Check user privileges on a foreign-data wrapper given
  2765. * name usename, foreign-data wrapper oid, and text priv name.
  2766. */
  2767. Datum
  2768. has_foreign_data_wrapper_privilege_name_id(PG_FUNCTION_ARGS)
  2769. {
  2770. Name username = PG_GETARG_NAME(0);
  2771. Oid fdwid = PG_GETARG_OID(1);
  2772. text *priv_type_text = PG_GETARG_TEXT_PP(2);
  2773. Oid roleid;
  2774. AclMode mode;
  2775. AclResult aclresult;
  2776. roleid = get_role_oid_or_public(NameStr(*username));
  2777. mode = convert_foreign_data_wrapper_priv_string(priv_type_text);
  2778. if (!SearchSysCacheExists1(FOREIGNDATAWRAPPEROID, ObjectIdGetDatum(fdwid)))
  2779. PG_RETURN_NULL();
  2780. aclresult = pg_foreign_data_wrapper_aclcheck(fdwid, roleid, mode);
  2781. PG_RETURN_BOOL(aclresult == ACLCHECK_OK);
  2782. }
  2783. /*
  2784. * has_foreign_data_wrapper_privilege_id
  2785. * Check user privileges on a foreign-data wrapper given
  2786. * foreign-data wrapper oid, and text priv name.
  2787. * current_user is assumed
  2788. */
  2789. Datum
  2790. has_foreign_data_wrapper_privilege_id(PG_FUNCTION_ARGS)
  2791. {
  2792. Oid fdwid = PG_GETARG_OID(0);
  2793. text *priv_type_text = PG_GETARG_TEXT_PP(1);
  2794. Oid roleid;
  2795. AclMode mode;
  2796. AclResult aclresult;
  2797. roleid = GetUserId();
  2798. mode = convert_foreign_data_wrapper_priv_string(priv_type_text);
  2799. if (!SearchSysCacheExists1(FOREIGNDATAWRAPPEROID, ObjectIdGetDatum(fdwid)))
  2800. PG_RETURN_NULL();
  2801. aclresult = pg_foreign_data_wrapper_aclcheck(fdwid, roleid, mode);
  2802. PG_RETURN_BOOL(aclresult == ACLCHECK_OK);
  2803. }
  2804. /*
  2805. * has_foreign_data_wrapper_privilege_id_name
  2806. * Check user privileges on a foreign-data wrapper given
  2807. * roleid, text fdwname, and text priv name.
  2808. */
  2809. Datum
  2810. has_foreign_data_wrapper_privilege_id_name(PG_FUNCTION_ARGS)
  2811. {
  2812. Oid roleid = PG_GETARG_OID(0);
  2813. text *fdwname = PG_GETARG_TEXT_PP(1);
  2814. text *priv_type_text = PG_GETARG_TEXT_PP(2);
  2815. Oid fdwid;
  2816. AclMode mode;
  2817. AclResult aclresult;
  2818. fdwid = convert_foreign_data_wrapper_name(fdwname);
  2819. mode = convert_foreign_data_wrapper_priv_string(priv_type_text);
  2820. aclresult = pg_foreign_data_wrapper_aclcheck(fdwid, roleid, mode);
  2821. PG_RETURN_BOOL(aclresult == ACLCHECK_OK);
  2822. }
  2823. /*
  2824. * has_foreign_data_wrapper_privilege_id_id
  2825. * Check user privileges on a foreign-data wrapper given
  2826. * roleid, fdw oid, and text priv name.
  2827. */
  2828. Datum
  2829. has_foreign_data_wrapper_privilege_id_id(PG_FUNCTION_ARGS)
  2830. {
  2831. Oid roleid = PG_GETARG_OID(0);
  2832. Oid fdwid = PG_GETARG_OID(1);
  2833. text *priv_type_text = PG_GETARG_TEXT_PP(2);
  2834. AclMode mode;
  2835. AclResult aclresult;
  2836. mode = convert_foreign_data_wrapper_priv_string(priv_type_text);
  2837. if (!SearchSysCacheExists1(FOREIGNDATAWRAPPEROID, ObjectIdGetDatum(fdwid)))
  2838. PG_RETURN_NULL();
  2839. aclresult = pg_foreign_data_wrapper_aclcheck(fdwid, roleid, mode);
  2840. PG_RETURN_BOOL(aclresult == ACLCHECK_OK);
  2841. }
  2842. /*
  2843. * Support routines for has_foreign_data_wrapper_privilege family.
  2844. */
  2845. /*
  2846. * Given a FDW name expressed as a string, look it up and return Oid
  2847. */
  2848. static Oid
  2849. convert_foreign_data_wrapper_name(text *fdwname)
  2850. {
  2851. char *fdwstr = text_to_cstring(fdwname);
  2852. return get_foreign_data_wrapper_oid(fdwstr, false);
  2853. }
  2854. /*
  2855. * convert_foreign_data_wrapper_priv_string
  2856. * Convert text string to AclMode value.
  2857. */
  2858. static AclMode
  2859. convert_foreign_data_wrapper_priv_string(text *priv_type_text)
  2860. {
  2861. static const priv_map foreign_data_wrapper_priv_map[] = {
  2862. {"USAGE", ACL_USAGE},
  2863. {"USAGE WITH GRANT OPTION", ACL_GRANT_OPTION_FOR(ACL_USAGE)},
  2864. {NULL, 0}
  2865. };
  2866. return convert_any_priv_string(priv_type_text, foreign_data_wrapper_priv_map);
  2867. }
  2868. /*
  2869. * has_function_privilege variants
  2870. * These are all named "has_function_privilege" at the SQL level.
  2871. * They take various combinations of function name, function OID,
  2872. * user name, user OID, or implicit user = current_user.
  2873. *
  2874. * The result is a boolean value: true if user has the indicated
  2875. * privilege, false if not, or NULL if object doesn't exist.
  2876. */
  2877. /*
  2878. * has_function_privilege_name_name
  2879. * Check user privileges on a function given
  2880. * name username, text functionname, and text priv name.
  2881. */
  2882. Datum
  2883. has_function_privilege_name_name(PG_FUNCTION_ARGS)
  2884. {
  2885. Name username = PG_GETARG_NAME(0);
  2886. text *functionname = PG_GETARG_TEXT_PP(1);
  2887. text *priv_type_text = PG_GETARG_TEXT_PP(2);
  2888. Oid roleid;
  2889. Oid functionoid;
  2890. AclMode mode;
  2891. AclResult aclresult;
  2892. roleid = get_role_oid_or_public(NameStr(*username));
  2893. functionoid = convert_function_name(functionname);
  2894. mode = convert_function_priv_string(priv_type_text);
  2895. aclresult = pg_proc_aclcheck(functionoid, roleid, mode);
  2896. PG_RETURN_BOOL(aclresult == ACLCHECK_OK);
  2897. }
  2898. /*
  2899. * has_function_privilege_name
  2900. * Check user privileges on a function given
  2901. * text functionname and text priv name.
  2902. * current_user is assumed
  2903. */
  2904. Datum
  2905. has_function_privilege_name(PG_FUNCTION_ARGS)
  2906. {
  2907. text *functionname = PG_GETARG_TEXT_PP(0);
  2908. text *priv_type_text = PG_GETARG_TEXT_PP(1);
  2909. Oid roleid;
  2910. Oid functionoid;
  2911. AclMode mode;
  2912. AclResult aclresult;
  2913. roleid = GetUserId();
  2914. functionoid = convert_function_name(functionname);
  2915. mode = convert_function_priv_string(priv_type_text);
  2916. aclresult = pg_proc_aclcheck(functionoid, roleid, mode);
  2917. PG_RETURN_BOOL(aclresult == ACLCHECK_OK);
  2918. }
  2919. /*
  2920. * has_function_privilege_name_id
  2921. * Check user privileges on a function given
  2922. * name usename, function oid, and text priv name.
  2923. */
  2924. Datum
  2925. has_function_privilege_name_id(PG_FUNCTION_ARGS)
  2926. {
  2927. Name username = PG_GETARG_NAME(0);
  2928. Oid functionoid = PG_GETARG_OID(1);
  2929. text *priv_type_text = PG_GETARG_TEXT_PP(2);
  2930. Oid roleid;
  2931. AclMode mode;
  2932. AclResult aclresult;
  2933. roleid = get_role_oid_or_public(NameStr(*username));
  2934. mode = convert_function_priv_string(priv_type_text);
  2935. if (!SearchSysCacheExists1(PROCOID, ObjectIdGetDatum(functionoid)))
  2936. PG_RETURN_NULL();
  2937. aclresult = pg_proc_aclcheck(functionoid, roleid, mode);
  2938. PG_RETURN_BOOL(aclresult == ACLCHECK_OK);
  2939. }
  2940. /*
  2941. * has_function_privilege_id
  2942. * Check user privileges on a function given
  2943. * function oid, and text priv name.
  2944. * current_user is assumed
  2945. */
  2946. Datum
  2947. has_function_privilege_id(PG_FUNCTION_ARGS)
  2948. {
  2949. Oid functionoid = PG_GETARG_OID(0);
  2950. text *priv_type_text = PG_GETARG_TEXT_PP(1);
  2951. Oid roleid;
  2952. AclMode mode;
  2953. AclResult aclresult;
  2954. roleid = GetUserId();
  2955. mode = convert_function_priv_string(priv_type_text);
  2956. if (!SearchSysCacheExists1(PROCOID, ObjectIdGetDatum(functionoid)))
  2957. PG_RETURN_NULL();
  2958. aclresult = pg_proc_aclcheck(functionoid, roleid, mode);
  2959. PG_RETURN_BOOL(aclresult == ACLCHECK_OK);
  2960. }
  2961. /*
  2962. * has_function_privilege_id_name
  2963. * Check user privileges on a function given
  2964. * roleid, text functionname, and text priv name.
  2965. */
  2966. Datum
  2967. has_function_privilege_id_name(PG_FUNCTION_ARGS)
  2968. {
  2969. Oid roleid = PG_GETARG_OID(0);
  2970. text *functionname = PG_GETARG_TEXT_PP(1);
  2971. text *priv_type_text = PG_GETARG_TEXT_PP(2);
  2972. Oid functionoid;
  2973. AclMode mode;
  2974. AclResult aclresult;
  2975. functionoid = convert_function_name(functionname);
  2976. mode = convert_function_priv_string(priv_type_text);
  2977. aclresult = pg_proc_aclcheck(functionoid, roleid, mode);
  2978. PG_RETURN_BOOL(aclresult == ACLCHECK_OK);
  2979. }
  2980. /*
  2981. * has_function_privilege_id_id
  2982. * Check user privileges on a function given
  2983. * roleid, function oid, and text priv name.
  2984. */
  2985. Datum
  2986. has_function_privilege_id_id(PG_FUNCTION_ARGS)
  2987. {
  2988. Oid roleid = PG_GETARG_OID(0);
  2989. Oid functionoid = PG_GETARG_OID(1);
  2990. text *priv_type_text = PG_GETARG_TEXT_PP(2);
  2991. AclMode mode;
  2992. AclResult aclresult;
  2993. mode = convert_function_priv_string(priv_type_text);
  2994. if (!SearchSysCacheExists1(PROCOID, ObjectIdGetDatum(functionoid)))
  2995. PG_RETURN_NULL();
  2996. aclresult = pg_proc_aclcheck(functionoid, roleid, mode);
  2997. PG_RETURN_BOOL(aclresult == ACLCHECK_OK);
  2998. }
  2999. /*
  3000. * Support routines for has_function_privilege family.
  3001. */
  3002. /*
  3003. * Given a function name expressed as a string, look it up and return Oid
  3004. */
  3005. static Oid
  3006. convert_function_name(text *functionname)
  3007. {
  3008. char *funcname = text_to_cstring(functionname);
  3009. Oid oid;
  3010. oid = DatumGetObjectId(DirectFunctionCall1(regprocedurein,
  3011. CStringGetDatum(funcname)));
  3012. if (!OidIsValid(oid))
  3013. ereport(ERROR,
  3014. (errcode(ERRCODE_UNDEFINED_FUNCTION),
  3015. errmsg("function \"%s\" does not exist", funcname)));
  3016. return oid;
  3017. }
  3018. /*
  3019. * convert_function_priv_string
  3020. * Convert text string to AclMode value.
  3021. */
  3022. static AclMode
  3023. convert_function_priv_string(text *priv_type_text)
  3024. {
  3025. static const priv_map function_priv_map[] = {
  3026. {"EXECUTE", ACL_EXECUTE},
  3027. {"EXECUTE WITH GRANT OPTION", ACL_GRANT_OPTION_FOR(ACL_EXECUTE)},
  3028. {NULL, 0}
  3029. };
  3030. return convert_any_priv_string(priv_type_text, function_priv_map);
  3031. }
  3032. /*
  3033. * has_language_privilege variants
  3034. * These are all named "has_language_privilege" at the SQL level.
  3035. * They take various combinations of language name, language OID,
  3036. * user name, user OID, or implicit user = current_user.
  3037. *
  3038. * The result is a boolean value: true if user has the indicated
  3039. * privilege, false if not, or NULL if object doesn't exist.
  3040. */
  3041. /*
  3042. * has_language_privilege_name_name
  3043. * Check user privileges on a language given
  3044. * name username, text languagename, and text priv name.
  3045. */
  3046. Datum
  3047. has_language_privilege_name_name(PG_FUNCTION_ARGS)
  3048. {
  3049. Name username = PG_GETARG_NAME(0);
  3050. text *languagename = PG_GETARG_TEXT_PP(1);
  3051. text *priv_type_text = PG_GETARG_TEXT_PP(2);
  3052. Oid roleid;
  3053. Oid languageoid;
  3054. AclMode mode;
  3055. AclResult aclresult;
  3056. roleid = get_role_oid_or_public(NameStr(*username));
  3057. languageoid = convert_language_name(languagename);
  3058. mode = convert_language_priv_string(priv_type_text);
  3059. aclresult = pg_language_aclcheck(languageoid, roleid, mode);
  3060. PG_RETURN_BOOL(aclresult == ACLCHECK_OK);
  3061. }
  3062. /*
  3063. * has_language_privilege_name
  3064. * Check user privileges on a language given
  3065. * text languagename and text priv name.
  3066. * current_user is assumed
  3067. */
  3068. Datum
  3069. has_language_privilege_name(PG_FUNCTION_ARGS)
  3070. {
  3071. text *languagename = PG_GETARG_TEXT_PP(0);
  3072. text *priv_type_text = PG_GETARG_TEXT_PP(1);
  3073. Oid roleid;
  3074. Oid languageoid;
  3075. AclMode mode;
  3076. AclResult aclresult;
  3077. roleid = GetUserId();
  3078. languageoid = convert_language_name(languagename);
  3079. mode = convert_language_priv_string(priv_type_text);
  3080. aclresult = pg_language_aclcheck(languageoid, roleid, mode);
  3081. PG_RETURN_BOOL(aclresult == ACLCHECK_OK);
  3082. }
  3083. /*
  3084. * has_language_privilege_name_id
  3085. * Check user privileges on a language given
  3086. * name usename, language oid, and text priv name.
  3087. */
  3088. Datum
  3089. has_language_privilege_name_id(PG_FUNCTION_ARGS)
  3090. {
  3091. Name username = PG_GETARG_NAME(0);
  3092. Oid languageoid = PG_GETARG_OID(1);
  3093. text *priv_type_text = PG_GETARG_TEXT_PP(2);
  3094. Oid roleid;
  3095. AclMode mode;
  3096. AclResult aclresult;
  3097. roleid = get_role_oid_or_public(NameStr(*username));
  3098. mode = convert_language_priv_string(priv_type_text);
  3099. if (!SearchSysCacheExists1(LANGOID, ObjectIdGetDatum(languageoid)))
  3100. PG_RETURN_NULL();
  3101. aclresult = pg_language_aclcheck(languageoid, roleid, mode);
  3102. PG_RETURN_BOOL(aclresult == ACLCHECK_OK);
  3103. }
  3104. /*
  3105. * has_language_privilege_id
  3106. * Check user privileges on a language given
  3107. * language oid, and text priv name.
  3108. * current_user is assumed
  3109. */
  3110. Datum
  3111. has_language_privilege_id(PG_FUNCTION_ARGS)
  3112. {
  3113. Oid languageoid = PG_GETARG_OID(0);
  3114. text *priv_type_text = PG_GETARG_TEXT_PP(1);
  3115. Oid roleid;
  3116. AclMode mode;
  3117. AclResult aclresult;
  3118. roleid = GetUserId();
  3119. mode = convert_language_priv_string(priv_type_text);
  3120. if (!SearchSysCacheExists1(LANGOID, ObjectIdGetDatum(languageoid)))
  3121. PG_RETURN_NULL();
  3122. aclresult = pg_language_aclcheck(languageoid, roleid, mode);
  3123. PG_RETURN_BOOL(aclresult == ACLCHECK_OK);
  3124. }
  3125. /*
  3126. * has_language_privilege_id_name
  3127. * Check user privileges on a language given
  3128. * roleid, text languagename, and text priv name.
  3129. */
  3130. Datum
  3131. has_language_privilege_id_name(PG_FUNCTION_ARGS)
  3132. {
  3133. Oid roleid = PG_GETARG_OID(0);
  3134. text *languagename = PG_GETARG_TEXT_PP(1);
  3135. text *priv_type_text = PG_GETARG_TEXT_PP(2);
  3136. Oid languageoid;
  3137. AclMode mode;
  3138. AclResult aclresult;
  3139. languageoid = convert_language_name(languagename);
  3140. mode = convert_language_priv_string(priv_type_text);
  3141. aclresult = pg_language_aclcheck(languageoid, roleid, mode);
  3142. PG_RETURN_BOOL(aclresult == ACLCHECK_OK);
  3143. }
  3144. /*
  3145. * has_language_privilege_id_id
  3146. * Check user privileges on a language given
  3147. * roleid, language oid, and text priv name.
  3148. */
  3149. Datum
  3150. has_language_privilege_id_id(PG_FUNCTION_ARGS)
  3151. {
  3152. Oid roleid = PG_GETARG_OID(0);
  3153. Oid languageoid = PG_GETARG_OID(1);
  3154. text *priv_type_text = PG_GETARG_TEXT_PP(2);
  3155. AclMode mode;
  3156. AclResult aclresult;
  3157. mode = convert_language_priv_string(priv_type_text);
  3158. if (!SearchSysCacheExists1(LANGOID, ObjectIdGetDatum(languageoid)))
  3159. PG_RETURN_NULL();
  3160. aclresult = pg_language_aclcheck(languageoid, roleid, mode);
  3161. PG_RETURN_BOOL(aclresult == ACLCHECK_OK);
  3162. }
  3163. /*
  3164. * Support routines for has_language_privilege family.
  3165. */
  3166. /*
  3167. * Given a language name expressed as a string, look it up and return Oid
  3168. */
  3169. static Oid
  3170. convert_language_name(text *languagename)
  3171. {
  3172. char *langname = text_to_cstring(languagename);
  3173. return get_language_oid(langname, false);
  3174. }
  3175. /*
  3176. * convert_language_priv_string
  3177. * Convert text string to AclMode value.
  3178. */
  3179. static AclMode
  3180. convert_language_priv_string(text *priv_type_text)
  3181. {
  3182. static const priv_map language_priv_map[] = {
  3183. {"USAGE", ACL_USAGE},
  3184. {"USAGE WITH GRANT OPTION", ACL_GRANT_OPTION_FOR(ACL_USAGE)},
  3185. {NULL, 0}
  3186. };
  3187. return convert_any_priv_string(priv_type_text, language_priv_map);
  3188. }
  3189. /*
  3190. * has_schema_privilege variants
  3191. * These are all named "has_schema_privilege" at the SQL level.
  3192. * They take various combinations of schema name, schema OID,
  3193. * user name, user OID, or implicit user = current_user.
  3194. *
  3195. * The result is a boolean value: true if user has the indicated
  3196. * privilege, false if not, or NULL if object doesn't exist.
  3197. */
  3198. /*
  3199. * has_schema_privilege_name_name
  3200. * Check user privileges on a schema given
  3201. * name username, text schemaname, and text priv name.
  3202. */
  3203. Datum
  3204. has_schema_privilege_name_name(PG_FUNCTION_ARGS)
  3205. {
  3206. Name username = PG_GETARG_NAME(0);
  3207. text *schemaname = PG_GETARG_TEXT_PP(1);
  3208. text *priv_type_text = PG_GETARG_TEXT_PP(2);
  3209. Oid roleid;
  3210. Oid schemaoid;
  3211. AclMode mode;
  3212. AclResult aclresult;
  3213. roleid = get_role_oid_or_public(NameStr(*username));
  3214. schemaoid = convert_schema_name(schemaname);
  3215. mode = convert_schema_priv_string(priv_type_text);
  3216. aclresult = pg_namespace_aclcheck(schemaoid, roleid, mode);
  3217. PG_RETURN_BOOL(aclresult == ACLCHECK_OK);
  3218. }
  3219. /*
  3220. * has_schema_privilege_name
  3221. * Check user privileges on a schema given
  3222. * text schemaname and text priv name.
  3223. * current_user is assumed
  3224. */
  3225. Datum
  3226. has_schema_privilege_name(PG_FUNCTION_ARGS)
  3227. {
  3228. text *schemaname = PG_GETARG_TEXT_PP(0);
  3229. text *priv_type_text = PG_GETARG_TEXT_PP(1);
  3230. Oid roleid;
  3231. Oid schemaoid;
  3232. AclMode mode;
  3233. AclResult aclresult;
  3234. roleid = GetUserId();
  3235. schemaoid = convert_schema_name(schemaname);
  3236. mode = convert_schema_priv_string(priv_type_text);
  3237. aclresult = pg_namespace_aclcheck(schemaoid, roleid, mode);
  3238. PG_RETURN_BOOL(aclresult == ACLCHECK_OK);
  3239. }
  3240. /*
  3241. * has_schema_privilege_name_id
  3242. * Check user privileges on a schema given
  3243. * name usename, schema oid, and text priv name.
  3244. */
  3245. Datum
  3246. has_schema_privilege_name_id(PG_FUNCTION_ARGS)
  3247. {
  3248. Name username = PG_GETARG_NAME(0);
  3249. Oid schemaoid = PG_GETARG_OID(1);
  3250. text *priv_type_text = PG_GETARG_TEXT_PP(2);
  3251. Oid roleid;
  3252. AclMode mode;
  3253. AclResult aclresult;
  3254. roleid = get_role_oid_or_public(NameStr(*username));
  3255. mode = convert_schema_priv_string(priv_type_text);
  3256. if (!SearchSysCacheExists1(NAMESPACEOID, ObjectIdGetDatum(schemaoid)))
  3257. PG_RETURN_NULL();
  3258. aclresult = pg_namespace_aclcheck(schemaoid, roleid, mode);
  3259. PG_RETURN_BOOL(aclresult == ACLCHECK_OK);
  3260. }
  3261. /*
  3262. * has_schema_privilege_id
  3263. * Check user privileges on a schema given
  3264. * schema oid, and text priv name.
  3265. * current_user is assumed
  3266. */
  3267. Datum
  3268. has_schema_privilege_id(PG_FUNCTION_ARGS)
  3269. {
  3270. Oid schemaoid = PG_GETARG_OID(0);
  3271. text *priv_type_text = PG_GETARG_TEXT_PP(1);
  3272. Oid roleid;
  3273. AclMode mode;
  3274. AclResult aclresult;
  3275. roleid = GetUserId();
  3276. mode = convert_schema_priv_string(priv_type_text);
  3277. if (!SearchSysCacheExists1(NAMESPACEOID, ObjectIdGetDatum(schemaoid)))
  3278. PG_RETURN_NULL();
  3279. aclresult = pg_namespace_aclcheck(schemaoid, roleid, mode);
  3280. PG_RETURN_BOOL(aclresult == ACLCHECK_OK);
  3281. }
  3282. /*
  3283. * has_schema_privilege_id_name
  3284. * Check user privileges on a schema given
  3285. * roleid, text schemaname, and text priv name.
  3286. */
  3287. Datum
  3288. has_schema_privilege_id_name(PG_FUNCTION_ARGS)
  3289. {
  3290. Oid roleid = PG_GETARG_OID(0);
  3291. text *schemaname = PG_GETARG_TEXT_PP(1);
  3292. text *priv_type_text = PG_GETARG_TEXT_PP(2);
  3293. Oid schemaoid;
  3294. AclMode mode;
  3295. AclResult aclresult;
  3296. schemaoid = convert_schema_name(schemaname);
  3297. mode = convert_schema_priv_string(priv_type_text);
  3298. aclresult = pg_namespace_aclcheck(schemaoid, roleid, mode);
  3299. PG_RETURN_BOOL(aclresult == ACLCHECK_OK);
  3300. }
  3301. /*
  3302. * has_schema_privilege_id_id
  3303. * Check user privileges on a schema given
  3304. * roleid, schema oid, and text priv name.
  3305. */
  3306. Datum
  3307. has_schema_privilege_id_id(PG_FUNCTION_ARGS)
  3308. {
  3309. Oid roleid = PG_GETARG_OID(0);
  3310. Oid schemaoid = PG_GETARG_OID(1);
  3311. text *priv_type_text = PG_GETARG_TEXT_PP(2);
  3312. AclMode mode;
  3313. AclResult aclresult;
  3314. mode = convert_schema_priv_string(priv_type_text);
  3315. if (!SearchSysCacheExists1(NAMESPACEOID, ObjectIdGetDatum(schemaoid)))
  3316. PG_RETURN_NULL();
  3317. aclresult = pg_namespace_aclcheck(schemaoid, roleid, mode);
  3318. PG_RETURN_BOOL(aclresult == ACLCHECK_OK);
  3319. }
  3320. /*
  3321. * Support routines for has_schema_privilege family.
  3322. */
  3323. /*
  3324. * Given a schema name expressed as a string, look it up and return Oid
  3325. */
  3326. static Oid
  3327. convert_schema_name(text *schemaname)
  3328. {
  3329. char *nspname = text_to_cstring(schemaname);
  3330. return get_namespace_oid(nspname, false);
  3331. }
  3332. /*
  3333. * convert_schema_priv_string
  3334. * Convert text string to AclMode value.
  3335. */
  3336. static AclMode
  3337. convert_schema_priv_string(text *priv_type_text)
  3338. {
  3339. static const priv_map schema_priv_map[] = {
  3340. {"CREATE", ACL_CREATE},
  3341. {"CREATE WITH GRANT OPTION", ACL_GRANT_OPTION_FOR(ACL_CREATE)},
  3342. {"USAGE", ACL_USAGE},
  3343. {"USAGE WITH GRANT OPTION", ACL_GRANT_OPTION_FOR(ACL_USAGE)},
  3344. {NULL, 0}
  3345. };
  3346. return convert_any_priv_string(priv_type_text, schema_priv_map);
  3347. }
  3348. /*
  3349. * has_server_privilege variants
  3350. * These are all named "has_server_privilege" at the SQL level.
  3351. * They take various combinations of foreign server name,
  3352. * server OID, user name, user OID, or implicit user = current_user.
  3353. *
  3354. * The result is a boolean value: true if user has the indicated
  3355. * privilege, false if not.
  3356. */
  3357. /*
  3358. * has_server_privilege_name_name
  3359. * Check user privileges on a foreign server given
  3360. * name username, text servername, and text priv name.
  3361. */
  3362. Datum
  3363. has_server_privilege_name_name(PG_FUNCTION_ARGS)
  3364. {
  3365. Name username = PG_GETARG_NAME(0);
  3366. text *servername = PG_GETARG_TEXT_PP(1);
  3367. text *priv_type_text = PG_GETARG_TEXT_PP(2);
  3368. Oid roleid;
  3369. Oid serverid;
  3370. AclMode mode;
  3371. AclResult aclresult;
  3372. roleid = get_role_oid_or_public(NameStr(*username));
  3373. serverid = convert_server_name(servername);
  3374. mode = convert_server_priv_string(priv_type_text);
  3375. aclresult = pg_foreign_server_aclcheck(serverid, roleid, mode);
  3376. PG_RETURN_BOOL(aclresult == ACLCHECK_OK);
  3377. }
  3378. /*
  3379. * has_server_privilege_name
  3380. * Check user privileges on a foreign server given
  3381. * text servername and text priv name.
  3382. * current_user is assumed
  3383. */
  3384. Datum
  3385. has_server_privilege_name(PG_FUNCTION_ARGS)
  3386. {
  3387. text *servername = PG_GETARG_TEXT_PP(0);
  3388. text *priv_type_text = PG_GETARG_TEXT_PP(1);
  3389. Oid roleid;
  3390. Oid serverid;
  3391. AclMode mode;
  3392. AclResult aclresult;
  3393. roleid = GetUserId();
  3394. serverid = convert_server_name(servername);
  3395. mode = convert_server_priv_string(priv_type_text);
  3396. aclresult = pg_foreign_server_aclcheck(serverid, roleid, mode);
  3397. PG_RETURN_BOOL(aclresult == ACLCHECK_OK);
  3398. }
  3399. /*
  3400. * has_server_privilege_name_id
  3401. * Check user privileges on a foreign server given
  3402. * name usename, foreign server oid, and text priv name.
  3403. */
  3404. Datum
  3405. has_server_privilege_name_id(PG_FUNCTION_ARGS)
  3406. {
  3407. Name username = PG_GETARG_NAME(0);
  3408. Oid serverid = PG_GETARG_OID(1);
  3409. text *priv_type_text = PG_GETARG_TEXT_PP(2);
  3410. Oid roleid;
  3411. AclMode mode;
  3412. AclResult aclresult;
  3413. roleid = get_role_oid_or_public(NameStr(*username));
  3414. mode = convert_server_priv_string(priv_type_text);
  3415. if (!SearchSysCacheExists1(FOREIGNSERVEROID, ObjectIdGetDatum(serverid)))
  3416. PG_RETURN_NULL();
  3417. aclresult = pg_foreign_server_aclcheck(serverid, roleid, mode);
  3418. PG_RETURN_BOOL(aclresult == ACLCHECK_OK);
  3419. }
  3420. /*
  3421. * has_server_privilege_id
  3422. * Check user privileges on a foreign server given
  3423. * server oid, and text priv name.
  3424. * current_user is assumed
  3425. */
  3426. Datum
  3427. has_server_privilege_id(PG_FUNCTION_ARGS)
  3428. {
  3429. Oid serverid = PG_GETARG_OID(0);
  3430. text *priv_type_text = PG_GETARG_TEXT_PP(1);
  3431. Oid roleid;
  3432. AclMode mode;
  3433. AclResult aclresult;
  3434. roleid = GetUserId();
  3435. mode = convert_server_priv_string(priv_type_text);
  3436. if (!SearchSysCacheExists1(FOREIGNSERVEROID, ObjectIdGetDatum(serverid)))
  3437. PG_RETURN_NULL();
  3438. aclresult = pg_foreign_server_aclcheck(serverid, roleid, mode);
  3439. PG_RETURN_BOOL(aclresult == ACLCHECK_OK);
  3440. }
  3441. /*
  3442. * has_server_privilege_id_name
  3443. * Check user privileges on a foreign server given
  3444. * roleid, text servername, and text priv name.
  3445. */
  3446. Datum
  3447. has_server_privilege_id_name(PG_FUNCTION_ARGS)
  3448. {
  3449. Oid roleid = PG_GETARG_OID(0);
  3450. text *servername = PG_GETARG_TEXT_PP(1);
  3451. text *priv_type_text = PG_GETARG_TEXT_PP(2);
  3452. Oid serverid;
  3453. AclMode mode;
  3454. AclResult aclresult;
  3455. serverid = convert_server_name(servername);
  3456. mode = convert_server_priv_string(priv_type_text);
  3457. aclresult = pg_foreign_server_aclcheck(serverid, roleid, mode);
  3458. PG_RETURN_BOOL(aclresult == ACLCHECK_OK);
  3459. }
  3460. /*
  3461. * has_server_privilege_id_id
  3462. * Check user privileges on a foreign server given
  3463. * roleid, server oid, and text priv name.
  3464. */
  3465. Datum
  3466. has_server_privilege_id_id(PG_FUNCTION_ARGS)
  3467. {
  3468. Oid roleid = PG_GETARG_OID(0);
  3469. Oid serverid = PG_GETARG_OID(1);
  3470. text *priv_type_text = PG_GETARG_TEXT_PP(2);
  3471. AclMode mode;
  3472. AclResult aclresult;
  3473. mode = convert_server_priv_string(priv_type_text);
  3474. if (!SearchSysCacheExists1(FOREIGNSERVEROID, ObjectIdGetDatum(serverid)))
  3475. PG_RETURN_NULL();
  3476. aclresult = pg_foreign_server_aclcheck(serverid, roleid, mode);
  3477. PG_RETURN_BOOL(aclresult == ACLCHECK_OK);
  3478. }
  3479. /*
  3480. * Support routines for has_server_privilege family.
  3481. */
  3482. /*
  3483. * Given a server name expressed as a string, look it up and return Oid
  3484. */
  3485. static Oid
  3486. convert_server_name(text *servername)
  3487. {
  3488. char *serverstr = text_to_cstring(servername);
  3489. return get_foreign_server_oid(serverstr, false);
  3490. }
  3491. /*
  3492. * convert_server_priv_string
  3493. * Convert text string to AclMode value.
  3494. */
  3495. static AclMode
  3496. convert_server_priv_string(text *priv_type_text)
  3497. {
  3498. static const priv_map server_priv_map[] = {
  3499. {"USAGE", ACL_USAGE},
  3500. {"USAGE WITH GRANT OPTION", ACL_GRANT_OPTION_FOR(ACL_USAGE)},
  3501. {NULL, 0}
  3502. };
  3503. return convert_any_priv_string(priv_type_text, server_priv_map);
  3504. }
  3505. /*
  3506. * has_tablespace_privilege variants
  3507. * These are all named "has_tablespace_privilege" at the SQL level.
  3508. * They take various combinations of tablespace name, tablespace OID,
  3509. * user name, user OID, or implicit user = current_user.
  3510. *
  3511. * The result is a boolean value: true if user has the indicated
  3512. * privilege, false if not.
  3513. */
  3514. /*
  3515. * has_tablespace_privilege_name_name
  3516. * Check user privileges on a tablespace given
  3517. * name username, text tablespacename, and text priv name.
  3518. */
  3519. Datum
  3520. has_tablespace_privilege_name_name(PG_FUNCTION_ARGS)
  3521. {
  3522. Name username = PG_GETARG_NAME(0);
  3523. text *tablespacename = PG_GETARG_TEXT_PP(1);
  3524. text *priv_type_text = PG_GETARG_TEXT_PP(2);
  3525. Oid roleid;
  3526. Oid tablespaceoid;
  3527. AclMode mode;
  3528. AclResult aclresult;
  3529. roleid = get_role_oid_or_public(NameStr(*username));
  3530. tablespaceoid = convert_tablespace_name(tablespacename);
  3531. mode = convert_tablespace_priv_string(priv_type_text);
  3532. aclresult = pg_tablespace_aclcheck(tablespaceoid, roleid, mode);
  3533. PG_RETURN_BOOL(aclresult == ACLCHECK_OK);
  3534. }
  3535. /*
  3536. * has_tablespace_privilege_name
  3537. * Check user privileges on a tablespace given
  3538. * text tablespacename and text priv name.
  3539. * current_user is assumed
  3540. */
  3541. Datum
  3542. has_tablespace_privilege_name(PG_FUNCTION_ARGS)
  3543. {
  3544. text *tablespacename = PG_GETARG_TEXT_PP(0);
  3545. text *priv_type_text = PG_GETARG_TEXT_PP(1);
  3546. Oid roleid;
  3547. Oid tablespaceoid;
  3548. AclMode mode;
  3549. AclResult aclresult;
  3550. roleid = GetUserId();
  3551. tablespaceoid = convert_tablespace_name(tablespacename);
  3552. mode = convert_tablespace_priv_string(priv_type_text);
  3553. aclresult = pg_tablespace_aclcheck(tablespaceoid, roleid, mode);
  3554. PG_RETURN_BOOL(aclresult == ACLCHECK_OK);
  3555. }
  3556. /*
  3557. * has_tablespace_privilege_name_id
  3558. * Check user privileges on a tablespace given
  3559. * name usename, tablespace oid, and text priv name.
  3560. */
  3561. Datum
  3562. has_tablespace_privilege_name_id(PG_FUNCTION_ARGS)
  3563. {
  3564. Name username = PG_GETARG_NAME(0);
  3565. Oid tablespaceoid = PG_GETARG_OID(1);
  3566. text *priv_type_text = PG_GETARG_TEXT_PP(2);
  3567. Oid roleid;
  3568. AclMode mode;
  3569. AclResult aclresult;
  3570. roleid = get_role_oid_or_public(NameStr(*username));
  3571. mode = convert_tablespace_priv_string(priv_type_text);
  3572. if (!SearchSysCacheExists1(TABLESPACEOID, ObjectIdGetDatum(tablespaceoid)))
  3573. PG_RETURN_NULL();
  3574. aclresult = pg_tablespace_aclcheck(tablespaceoid, roleid, mode);
  3575. PG_RETURN_BOOL(aclresult == ACLCHECK_OK);
  3576. }
  3577. /*
  3578. * has_tablespace_privilege_id
  3579. * Check user privileges on a tablespace given
  3580. * tablespace oid, and text priv name.
  3581. * current_user is assumed
  3582. */
  3583. Datum
  3584. has_tablespace_privilege_id(PG_FUNCTION_ARGS)
  3585. {
  3586. Oid tablespaceoid = PG_GETARG_OID(0);
  3587. text *priv_type_text = PG_GETARG_TEXT_PP(1);
  3588. Oid roleid;
  3589. AclMode mode;
  3590. AclResult aclresult;
  3591. roleid = GetUserId();
  3592. mode = convert_tablespace_priv_string(priv_type_text);
  3593. if (!SearchSysCacheExists1(TABLESPACEOID, ObjectIdGetDatum(tablespaceoid)))
  3594. PG_RETURN_NULL();
  3595. aclresult = pg_tablespace_aclcheck(tablespaceoid, roleid, mode);
  3596. PG_RETURN_BOOL(aclresult == ACLCHECK_OK);
  3597. }
  3598. /*
  3599. * has_tablespace_privilege_id_name
  3600. * Check user privileges on a tablespace given
  3601. * roleid, text tablespacename, and text priv name.
  3602. */
  3603. Datum
  3604. has_tablespace_privilege_id_name(PG_FUNCTION_ARGS)
  3605. {
  3606. Oid roleid = PG_GETARG_OID(0);
  3607. text *tablespacename = PG_GETARG_TEXT_PP(1);
  3608. text *priv_type_text = PG_GETARG_TEXT_PP(2);
  3609. Oid tablespaceoid;
  3610. AclMode mode;
  3611. AclResult aclresult;
  3612. tablespaceoid = convert_tablespace_name(tablespacename);
  3613. mode = convert_tablespace_priv_string(priv_type_text);
  3614. aclresult = pg_tablespace_aclcheck(tablespaceoid, roleid, mode);
  3615. PG_RETURN_BOOL(aclresult == ACLCHECK_OK);
  3616. }
  3617. /*
  3618. * has_tablespace_privilege_id_id
  3619. * Check user privileges on a tablespace given
  3620. * roleid, tablespace oid, and text priv name.
  3621. */
  3622. Datum
  3623. has_tablespace_privilege_id_id(PG_FUNCTION_ARGS)
  3624. {
  3625. Oid roleid = PG_GETARG_OID(0);
  3626. Oid tablespaceoid = PG_GETARG_OID(1);
  3627. text *priv_type_text = PG_GETARG_TEXT_PP(2);
  3628. AclMode mode;
  3629. AclResult aclresult;
  3630. mode = convert_tablespace_priv_string(priv_type_text);
  3631. if (!SearchSysCacheExists1(TABLESPACEOID, ObjectIdGetDatum(tablespaceoid)))
  3632. PG_RETURN_NULL();
  3633. aclresult = pg_tablespace_aclcheck(tablespaceoid, roleid, mode);
  3634. PG_RETURN_BOOL(aclresult == ACLCHECK_OK);
  3635. }
  3636. /*
  3637. * Support routines for has_tablespace_privilege family.
  3638. */
  3639. /*
  3640. * Given a tablespace name expressed as a string, look it up and return Oid
  3641. */
  3642. static Oid
  3643. convert_tablespace_name(text *tablespacename)
  3644. {
  3645. char *spcname = text_to_cstring(tablespacename);
  3646. return get_tablespace_oid(spcname, false);
  3647. }
  3648. /*
  3649. * convert_tablespace_priv_string
  3650. * Convert text string to AclMode value.
  3651. */
  3652. static AclMode
  3653. convert_tablespace_priv_string(text *priv_type_text)
  3654. {
  3655. static const priv_map tablespace_priv_map[] = {
  3656. {"CREATE", ACL_CREATE},
  3657. {"CREATE WITH GRANT OPTION", ACL_GRANT_OPTION_FOR(ACL_CREATE)},
  3658. {NULL, 0}
  3659. };
  3660. return convert_any_priv_string(priv_type_text, tablespace_priv_map);
  3661. }
  3662. /*
  3663. * has_type_privilege variants
  3664. * These are all named "has_type_privilege" at the SQL level.
  3665. * They take various combinations of type name, type OID,
  3666. * user name, user OID, or implicit user = current_user.
  3667. *
  3668. * The result is a boolean value: true if user has the indicated
  3669. * privilege, false if not, or NULL if object doesn't exist.
  3670. */
  3671. /*
  3672. * has_type_privilege_name_name
  3673. * Check user privileges on a type given
  3674. * name username, text typename, and text priv name.
  3675. */
  3676. Datum
  3677. has_type_privilege_name_name(PG_FUNCTION_ARGS)
  3678. {
  3679. Name username = PG_GETARG_NAME(0);
  3680. text *typename = PG_GETARG_TEXT_PP(1);
  3681. text *priv_type_text = PG_GETARG_TEXT_PP(2);
  3682. Oid roleid;
  3683. Oid typeoid;
  3684. AclMode mode;
  3685. AclResult aclresult;
  3686. roleid = get_role_oid_or_public(NameStr(*username));
  3687. typeoid = convert_type_name(typename);
  3688. mode = convert_type_priv_string(priv_type_text);
  3689. aclresult = pg_type_aclcheck(typeoid, roleid, mode);
  3690. PG_RETURN_BOOL(aclresult == ACLCHECK_OK);
  3691. }
  3692. /*
  3693. * has_type_privilege_name
  3694. * Check user privileges on a type given
  3695. * text typename and text priv name.
  3696. * current_user is assumed
  3697. */
  3698. Datum
  3699. has_type_privilege_name(PG_FUNCTION_ARGS)
  3700. {
  3701. text *typename = PG_GETARG_TEXT_PP(0);
  3702. text *priv_type_text = PG_GETARG_TEXT_PP(1);
  3703. Oid roleid;
  3704. Oid typeoid;
  3705. AclMode mode;
  3706. AclResult aclresult;
  3707. roleid = GetUserId();
  3708. typeoid = convert_type_name(typename);
  3709. mode = convert_type_priv_string(priv_type_text);
  3710. aclresult = pg_type_aclcheck(typeoid, roleid, mode);
  3711. PG_RETURN_BOOL(aclresult == ACLCHECK_OK);
  3712. }
  3713. /*
  3714. * has_type_privilege_name_id
  3715. * Check user privileges on a type given
  3716. * name usename, type oid, and text priv name.
  3717. */
  3718. Datum
  3719. has_type_privilege_name_id(PG_FUNCTION_ARGS)
  3720. {
  3721. Name username = PG_GETARG_NAME(0);
  3722. Oid typeoid = PG_GETARG_OID(1);
  3723. text *priv_type_text = PG_GETARG_TEXT_PP(2);
  3724. Oid roleid;
  3725. AclMode mode;
  3726. AclResult aclresult;
  3727. roleid = get_role_oid_or_public(NameStr(*username));
  3728. mode = convert_type_priv_string(priv_type_text);
  3729. if (!SearchSysCacheExists1(TYPEOID, ObjectIdGetDatum(typeoid)))
  3730. PG_RETURN_NULL();
  3731. aclresult = pg_type_aclcheck(typeoid, roleid, mode);
  3732. PG_RETURN_BOOL(aclresult == ACLCHECK_OK);
  3733. }
  3734. /*
  3735. * has_type_privilege_id
  3736. * Check user privileges on a type given
  3737. * type oid, and text priv name.
  3738. * current_user is assumed
  3739. */
  3740. Datum
  3741. has_type_privilege_id(PG_FUNCTION_ARGS)
  3742. {
  3743. Oid typeoid = PG_GETARG_OID(0);
  3744. text *priv_type_text = PG_GETARG_TEXT_PP(1);
  3745. Oid roleid;
  3746. AclMode mode;
  3747. AclResult aclresult;
  3748. roleid = GetUserId();
  3749. mode = convert_type_priv_string(priv_type_text);
  3750. if (!SearchSysCacheExists1(TYPEOID, ObjectIdGetDatum(typeoid)))
  3751. PG_RETURN_NULL();
  3752. aclresult = pg_type_aclcheck(typeoid, roleid, mode);
  3753. PG_RETURN_BOOL(aclresult == ACLCHECK_OK);
  3754. }
  3755. /*
  3756. * has_type_privilege_id_name
  3757. * Check user privileges on a type given
  3758. * roleid, text typename, and text priv name.
  3759. */
  3760. Datum
  3761. has_type_privilege_id_name(PG_FUNCTION_ARGS)
  3762. {
  3763. Oid roleid = PG_GETARG_OID(0);
  3764. text *typename = PG_GETARG_TEXT_PP(1);
  3765. text *priv_type_text = PG_GETARG_TEXT_PP(2);
  3766. Oid typeoid;
  3767. AclMode mode;
  3768. AclResult aclresult;
  3769. typeoid = convert_type_name(typename);
  3770. mode = convert_type_priv_string(priv_type_text);
  3771. aclresult = pg_type_aclcheck(typeoid, roleid, mode);
  3772. PG_RETURN_BOOL(aclresult == ACLCHECK_OK);
  3773. }
  3774. /*
  3775. * has_type_privilege_id_id
  3776. * Check user privileges on a type given
  3777. * roleid, type oid, and text priv name.
  3778. */
  3779. Datum
  3780. has_type_privilege_id_id(PG_FUNCTION_ARGS)
  3781. {
  3782. Oid roleid = PG_GETARG_OID(0);
  3783. Oid typeoid = PG_GETARG_OID(1);
  3784. text *priv_type_text = PG_GETARG_TEXT_PP(2);
  3785. AclMode mode;
  3786. AclResult aclresult;
  3787. mode = convert_type_priv_string(priv_type_text);
  3788. if (!SearchSysCacheExists1(TYPEOID, ObjectIdGetDatum(typeoid)))
  3789. PG_RETURN_NULL();
  3790. aclresult = pg_type_aclcheck(typeoid, roleid, mode);
  3791. PG_RETURN_BOOL(aclresult == ACLCHECK_OK);
  3792. }
  3793. /*
  3794. * Support routines for has_type_privilege family.
  3795. */
  3796. /*
  3797. * Given a type name expressed as a string, look it up and return Oid
  3798. */
  3799. static Oid
  3800. convert_type_name(text *typename)
  3801. {
  3802. char *typname = text_to_cstring(typename);
  3803. Oid oid;
  3804. oid = DatumGetObjectId(DirectFunctionCall1(regtypein,
  3805. CStringGetDatum(typname)));
  3806. if (!OidIsValid(oid))
  3807. ereport(ERROR,
  3808. (errcode(ERRCODE_UNDEFINED_OBJECT),
  3809. errmsg("type \"%s\" does not exist", typname)));
  3810. return oid;
  3811. }
  3812. /*
  3813. * convert_type_priv_string
  3814. * Convert text string to AclMode value.
  3815. */
  3816. static AclMode
  3817. convert_type_priv_string(text *priv_type_text)
  3818. {
  3819. static const priv_map type_priv_map[] = {
  3820. {"USAGE", ACL_USAGE},
  3821. {"USAGE WITH GRANT OPTION", ACL_GRANT_OPTION_FOR(ACL_USAGE)},
  3822. {NULL, 0}
  3823. };
  3824. return convert_any_priv_string(priv_type_text, type_priv_map);
  3825. }
  3826. /*
  3827. * pg_has_role variants
  3828. * These are all named "pg_has_role" at the SQL level.
  3829. * They take various combinations of role name, role OID,
  3830. * user name, user OID, or implicit user = current_user.
  3831. *
  3832. * The result is a boolean value: true if user has the indicated
  3833. * privilege, false if not.
  3834. */
  3835. /*
  3836. * pg_has_role_name_name
  3837. * Check user privileges on a role given
  3838. * name username, name rolename, and text priv name.
  3839. */
  3840. Datum
  3841. pg_has_role_name_name(PG_FUNCTION_ARGS)
  3842. {
  3843. Name username = PG_GETARG_NAME(0);
  3844. Name rolename = PG_GETARG_NAME(1);
  3845. text *priv_type_text = PG_GETARG_TEXT_PP(2);
  3846. Oid roleid;
  3847. Oid roleoid;
  3848. AclMode mode;
  3849. AclResult aclresult;
  3850. roleid = get_role_oid(NameStr(*username), false);
  3851. roleoid = get_role_oid(NameStr(*rolename), false);
  3852. mode = convert_role_priv_string(priv_type_text);
  3853. aclresult = pg_role_aclcheck(roleoid, roleid, mode);
  3854. PG_RETURN_BOOL(aclresult == ACLCHECK_OK);
  3855. }
  3856. /*
  3857. * pg_has_role_name
  3858. * Check user privileges on a role given
  3859. * name rolename and text priv name.
  3860. * current_user is assumed
  3861. */
  3862. Datum
  3863. pg_has_role_name(PG_FUNCTION_ARGS)
  3864. {
  3865. Name rolename = PG_GETARG_NAME(0);
  3866. text *priv_type_text = PG_GETARG_TEXT_PP(1);
  3867. Oid roleid;
  3868. Oid roleoid;
  3869. AclMode mode;
  3870. AclResult aclresult;
  3871. roleid = GetUserId();
  3872. roleoid = get_role_oid(NameStr(*rolename), false);
  3873. mode = convert_role_priv_string(priv_type_text);
  3874. aclresult = pg_role_aclcheck(roleoid, roleid, mode);
  3875. PG_RETURN_BOOL(aclresult == ACLCHECK_OK);
  3876. }
  3877. /*
  3878. * pg_has_role_name_id
  3879. * Check user privileges on a role given
  3880. * name usename, role oid, and text priv name.
  3881. */
  3882. Datum
  3883. pg_has_role_name_id(PG_FUNCTION_ARGS)
  3884. {
  3885. Name username = PG_GETARG_NAME(0);
  3886. Oid roleoid = PG_GETARG_OID(1);
  3887. text *priv_type_text = PG_GETARG_TEXT_PP(2);
  3888. Oid roleid;
  3889. AclMode mode;
  3890. AclResult aclresult;
  3891. roleid = get_role_oid(NameStr(*username), false);
  3892. mode = convert_role_priv_string(priv_type_text);
  3893. aclresult = pg_role_aclcheck(roleoid, roleid, mode);
  3894. PG_RETURN_BOOL(aclresult == ACLCHECK_OK);
  3895. }
  3896. /*
  3897. * pg_has_role_id
  3898. * Check user privileges on a role given
  3899. * role oid, and text priv name.
  3900. * current_user is assumed
  3901. */
  3902. Datum
  3903. pg_has_role_id(PG_FUNCTION_ARGS)
  3904. {
  3905. Oid roleoid = PG_GETARG_OID(0);
  3906. text *priv_type_text = PG_GETARG_TEXT_PP(1);
  3907. Oid roleid;
  3908. AclMode mode;
  3909. AclResult aclresult;
  3910. roleid = GetUserId();
  3911. mode = convert_role_priv_string(priv_type_text);
  3912. aclresult = pg_role_aclcheck(roleoid, roleid, mode);
  3913. PG_RETURN_BOOL(aclresult == ACLCHECK_OK);
  3914. }
  3915. /*
  3916. * pg_has_role_id_name
  3917. * Check user privileges on a role given
  3918. * roleid, name rolename, and text priv name.
  3919. */
  3920. Datum
  3921. pg_has_role_id_name(PG_FUNCTION_ARGS)
  3922. {
  3923. Oid roleid = PG_GETARG_OID(0);
  3924. Name rolename = PG_GETARG_NAME(1);
  3925. text *priv_type_text = PG_GETARG_TEXT_PP(2);
  3926. Oid roleoid;
  3927. AclMode mode;
  3928. AclResult aclresult;
  3929. roleoid = get_role_oid(NameStr(*rolename), false);
  3930. mode = convert_role_priv_string(priv_type_text);
  3931. aclresult = pg_role_aclcheck(roleoid, roleid, mode);
  3932. PG_RETURN_BOOL(aclresult == ACLCHECK_OK);
  3933. }
  3934. /*
  3935. * pg_has_role_id_id
  3936. * Check user privileges on a role given
  3937. * roleid, role oid, and text priv name.
  3938. */
  3939. Datum
  3940. pg_has_role_id_id(PG_FUNCTION_ARGS)
  3941. {
  3942. Oid roleid = PG_GETARG_OID(0);
  3943. Oid roleoid = PG_GETARG_OID(1);
  3944. text *priv_type_text = PG_GETARG_TEXT_PP(2);
  3945. AclMode mode;
  3946. AclResult aclresult;
  3947. mode = convert_role_priv_string(priv_type_text);
  3948. aclresult = pg_role_aclcheck(roleoid, roleid, mode);
  3949. PG_RETURN_BOOL(aclresult == ACLCHECK_OK);
  3950. }
  3951. /*
  3952. * Support routines for pg_has_role family.
  3953. */
  3954. /*
  3955. * convert_role_priv_string
  3956. * Convert text string to AclMode value.
  3957. *
  3958. * We use USAGE to denote whether the privileges of the role are accessible
  3959. * (has_privs), MEMBER to denote is_member, and MEMBER WITH GRANT OPTION
  3960. * (or ADMIN OPTION) to denote is_admin. There is no ACL bit corresponding
  3961. * to MEMBER so we cheat and use ACL_CREATE for that. This convention
  3962. * is shared only with pg_role_aclcheck, below.
  3963. */
  3964. static AclMode
  3965. convert_role_priv_string(text *priv_type_text)
  3966. {
  3967. static const priv_map role_priv_map[] = {
  3968. {"USAGE", ACL_USAGE},
  3969. {"MEMBER", ACL_CREATE},
  3970. {"USAGE WITH GRANT OPTION", ACL_GRANT_OPTION_FOR(ACL_CREATE)},
  3971. {"USAGE WITH ADMIN OPTION", ACL_GRANT_OPTION_FOR(ACL_CREATE)},
  3972. {"MEMBER WITH GRANT OPTION", ACL_GRANT_OPTION_FOR(ACL_CREATE)},
  3973. {"MEMBER WITH ADMIN OPTION", ACL_GRANT_OPTION_FOR(ACL_CREATE)},
  3974. {NULL, 0}
  3975. };
  3976. return convert_any_priv_string(priv_type_text, role_priv_map);
  3977. }
  3978. /*
  3979. * pg_role_aclcheck
  3980. * Quick-and-dirty support for pg_has_role
  3981. */
  3982. static AclResult
  3983. pg_role_aclcheck(Oid role_oid, Oid roleid, AclMode mode)
  3984. {
  3985. if (mode & ACL_GRANT_OPTION_FOR(ACL_CREATE))
  3986. {
  3987. /*
  3988. * XXX For roleid == role_oid, is_admin_of_role() also examines the
  3989. * session and call stack. That suits two-argument pg_has_role(), but
  3990. * it gives the three-argument version a lamentable whimsy.
  3991. */
  3992. if (is_admin_of_role(roleid, role_oid))
  3993. return ACLCHECK_OK;
  3994. }
  3995. if (mode & ACL_CREATE)
  3996. {
  3997. if (is_member_of_role(roleid, role_oid))
  3998. return ACLCHECK_OK;
  3999. }
  4000. if (mode & ACL_USAGE)
  4001. {
  4002. if (has_privs_of_role(roleid, role_oid))
  4003. return ACLCHECK_OK;
  4004. }
  4005. return ACLCHECK_NO_PRIV;
  4006. }
  4007. /*
  4008. * initialization function (called by InitPostgres)
  4009. */
  4010. void
  4011. initialize_acl(void)
  4012. {
  4013. if (!IsBootstrapProcessingMode())
  4014. {
  4015. /*
  4016. * In normal mode, set a callback on any syscache invalidation of
  4017. * pg_auth_members rows
  4018. */
  4019. CacheRegisterSyscacheCallback(AUTHMEMROLEMEM,
  4020. RoleMembershipCacheCallback,
  4021. (Datum) 0);
  4022. }
  4023. }
  4024. /*
  4025. * RoleMembershipCacheCallback
  4026. * Syscache inval callback function
  4027. */
  4028. static void
  4029. RoleMembershipCacheCallback(Datum arg, int cacheid, uint32 hashvalue)
  4030. {
  4031. /* Force membership caches to be recomputed on next use */
  4032. cached_privs_role = InvalidOid;
  4033. cached_member_role = InvalidOid;
  4034. }
  4035. /* Check if specified role has rolinherit set */
  4036. static bool
  4037. has_rolinherit(Oid roleid)
  4038. {
  4039. bool result = false;
  4040. HeapTuple utup;
  4041. utup = SearchSysCache1(AUTHOID, ObjectIdGetDatum(roleid));
  4042. if (HeapTupleIsValid(utup))
  4043. {
  4044. result = ((Form_pg_authid) GETSTRUCT(utup))->rolinherit;
  4045. ReleaseSysCache(utup);
  4046. }
  4047. return result;
  4048. }
  4049. /*
  4050. * Get a list of roles that the specified roleid has the privileges of
  4051. *
  4052. * This is defined not to recurse through roles that don't have rolinherit
  4053. * set; for such roles, membership implies the ability to do SET ROLE, but
  4054. * the privileges are not available until you've done so.
  4055. *
  4056. * Since indirect membership testing is relatively expensive, we cache
  4057. * a list of memberships. Hence, the result is only guaranteed good until
  4058. * the next call of roles_has_privs_of()!
  4059. *
  4060. * For the benefit of select_best_grantor, the result is defined to be
  4061. * in breadth-first order, ie, closer relationships earlier.
  4062. */
  4063. static List *
  4064. roles_has_privs_of(Oid roleid)
  4065. {
  4066. List *roles_list;
  4067. ListCell *l;
  4068. List *new_cached_privs_roles;
  4069. MemoryContext oldctx;
  4070. /* If cache is already valid, just return the list */
  4071. if (OidIsValid(cached_privs_role) && cached_privs_role == roleid)
  4072. return cached_privs_roles;
  4073. /*
  4074. * Find all the roles that roleid is a member of, including multi-level
  4075. * recursion. The role itself will always be the first element of the
  4076. * resulting list.
  4077. *
  4078. * Each element of the list is scanned to see if it adds any indirect
  4079. * memberships. We can use a single list as both the record of
  4080. * already-found memberships and the agenda of roles yet to be scanned.
  4081. * This is a bit tricky but works because the foreach() macro doesn't
  4082. * fetch the next list element until the bottom of the loop.
  4083. */
  4084. roles_list = list_make1_oid(roleid);
  4085. foreach(l, roles_list)
  4086. {
  4087. Oid memberid = lfirst_oid(l);
  4088. CatCList *memlist;
  4089. int i;
  4090. /* Ignore non-inheriting roles */
  4091. if (!has_rolinherit(memberid))
  4092. continue;
  4093. /* Find roles that memberid is directly a member of */
  4094. memlist = SearchSysCacheList1(AUTHMEMMEMROLE,
  4095. ObjectIdGetDatum(memberid));
  4096. for (i = 0; i < memlist->n_members; i++)
  4097. {
  4098. HeapTuple tup = &memlist->members[i]->tuple;
  4099. Oid otherid = ((Form_pg_auth_members) GETSTRUCT(tup))->roleid;
  4100. /*
  4101. * Even though there shouldn't be any loops in the membership
  4102. * graph, we must test for having already seen this role. It is
  4103. * legal for instance to have both A->B and A->C->B.
  4104. */
  4105. roles_list = list_append_unique_oid(roles_list, otherid);
  4106. }
  4107. ReleaseSysCacheList(memlist);
  4108. }
  4109. /*
  4110. * Copy the completed list into TopMemoryContext so it will persist.
  4111. */
  4112. oldctx = MemoryContextSwitchTo(TopMemoryContext);
  4113. new_cached_privs_roles = list_copy(roles_list);
  4114. MemoryContextSwitchTo(oldctx);
  4115. list_free(roles_list);
  4116. /*
  4117. * Now safe to assign to state variable
  4118. */
  4119. cached_privs_role = InvalidOid; /* just paranoia */
  4120. list_free(cached_privs_roles);
  4121. cached_privs_roles = new_cached_privs_roles;
  4122. cached_privs_role = roleid;
  4123. /* And now we can return the answer */
  4124. return cached_privs_roles;
  4125. }
  4126. /*
  4127. * Get a list of roles that the specified roleid is a member of
  4128. *
  4129. * This is defined to recurse through roles regardless of rolinherit.
  4130. *
  4131. * Since indirect membership testing is relatively expensive, we cache
  4132. * a list of memberships. Hence, the result is only guaranteed good until
  4133. * the next call of roles_is_member_of()!
  4134. */
  4135. static List *
  4136. roles_is_member_of(Oid roleid)
  4137. {
  4138. List *roles_list;
  4139. ListCell *l;
  4140. List *new_cached_membership_roles;
  4141. MemoryContext oldctx;
  4142. /* If cache is already valid, just return the list */
  4143. if (OidIsValid(cached_member_role) && cached_member_role == roleid)
  4144. return cached_membership_roles;
  4145. /*
  4146. * Find all the roles that roleid is a member of, including multi-level
  4147. * recursion. The role itself will always be the first element of the
  4148. * resulting list.
  4149. *
  4150. * Each element of the list is scanned to see if it adds any indirect
  4151. * memberships. We can use a single list as both the record of
  4152. * already-found memberships and the agenda of roles yet to be scanned.
  4153. * This is a bit tricky but works because the foreach() macro doesn't
  4154. * fetch the next list element until the bottom of the loop.
  4155. */
  4156. roles_list = list_make1_oid(roleid);
  4157. foreach(l, roles_list)
  4158. {
  4159. Oid memberid = lfirst_oid(l);
  4160. CatCList *memlist;
  4161. int i;
  4162. /* Find roles that memberid is directly a member of */
  4163. memlist = SearchSysCacheList1(AUTHMEMMEMROLE,
  4164. ObjectIdGetDatum(memberid));
  4165. for (i = 0; i < memlist->n_members; i++)
  4166. {
  4167. HeapTuple tup = &memlist->members[i]->tuple;
  4168. Oid otherid = ((Form_pg_auth_members) GETSTRUCT(tup))->roleid;
  4169. /*
  4170. * Even though there shouldn't be any loops in the membership
  4171. * graph, we must test for having already seen this role. It is
  4172. * legal for instance to have both A->B and A->C->B.
  4173. */
  4174. roles_list = list_append_unique_oid(roles_list, otherid);
  4175. }
  4176. ReleaseSysCacheList(memlist);
  4177. }
  4178. /*
  4179. * Copy the completed list into TopMemoryContext so it will persist.
  4180. */
  4181. oldctx = MemoryContextSwitchTo(TopMemoryContext);
  4182. new_cached_membership_roles = list_copy(roles_list);
  4183. MemoryContextSwitchTo(oldctx);
  4184. list_free(roles_list);
  4185. /*
  4186. * Now safe to assign to state variable
  4187. */
  4188. cached_member_role = InvalidOid; /* just paranoia */
  4189. list_free(cached_membership_roles);
  4190. cached_membership_roles = new_cached_membership_roles;
  4191. cached_member_role = roleid;
  4192. /* And now we can return the answer */
  4193. return cached_membership_roles;
  4194. }
  4195. /*
  4196. * Does member have the privileges of role (directly or indirectly)?
  4197. *
  4198. * This is defined not to recurse through roles that don't have rolinherit
  4199. * set; for such roles, membership implies the ability to do SET ROLE, but
  4200. * the privileges are not available until you've done so.
  4201. */
  4202. bool
  4203. has_privs_of_role(Oid member, Oid role)
  4204. {
  4205. /* Fast path for simple case */
  4206. if (member == role)
  4207. return true;
  4208. /* Superusers have every privilege, so are part of every role */
  4209. if (superuser_arg(member))
  4210. return true;
  4211. /*
  4212. * Find all the roles that member has the privileges of, including
  4213. * multi-level recursion, then see if target role is any one of them.
  4214. */
  4215. return list_member_oid(roles_has_privs_of(member), role);
  4216. }
  4217. /*
  4218. * Is member a member of role (directly or indirectly)?
  4219. *
  4220. * This is defined to recurse through roles regardless of rolinherit.
  4221. */
  4222. bool
  4223. is_member_of_role(Oid member, Oid role)
  4224. {
  4225. /* Fast path for simple case */
  4226. if (member == role)
  4227. return true;
  4228. /* Superusers have every privilege, so are part of every role */
  4229. if (superuser_arg(member))
  4230. return true;
  4231. /*
  4232. * Find all the roles that member is a member of, including multi-level
  4233. * recursion, then see if target role is any one of them.
  4234. */
  4235. return list_member_oid(roles_is_member_of(member), role);
  4236. }
  4237. /*
  4238. * check_is_member_of_role
  4239. * is_member_of_role with a standard permission-violation error if not
  4240. */
  4241. void
  4242. check_is_member_of_role(Oid member, Oid role)
  4243. {
  4244. if (!is_member_of_role(member, role))
  4245. ereport(ERROR,
  4246. (errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
  4247. errmsg("must be member of role \"%s\"",
  4248. GetUserNameFromId(role, false))));
  4249. }
  4250. /*
  4251. * Is member a member of role, not considering superuserness?
  4252. *
  4253. * This is identical to is_member_of_role except we ignore superuser
  4254. * status.
  4255. */
  4256. bool
  4257. is_member_of_role_nosuper(Oid member, Oid role)
  4258. {
  4259. /* Fast path for simple case */
  4260. if (member == role)
  4261. return true;
  4262. /*
  4263. * Find all the roles that member is a member of, including multi-level
  4264. * recursion, then see if target role is any one of them.
  4265. */
  4266. return list_member_oid(roles_is_member_of(member), role);
  4267. }
  4268. /*
  4269. * Is member an admin of role? That is, is member the role itself (subject to
  4270. * restrictions below), a member (directly or indirectly) WITH ADMIN OPTION,
  4271. * or a superuser?
  4272. */
  4273. bool
  4274. is_admin_of_role(Oid member, Oid role)
  4275. {
  4276. bool result = false;
  4277. List *roles_list;
  4278. ListCell *l;
  4279. if (superuser_arg(member))
  4280. return true;
  4281. if (member == role)
  4282. /*
  4283. * A role can admin itself when it matches the session user and we're
  4284. * outside any security-restricted operation, SECURITY DEFINER or
  4285. * similar context. SQL-standard roles cannot self-admin. However,
  4286. * SQL-standard users are distinct from roles, and they are not
  4287. * grantable like roles: PostgreSQL's role-user duality extends the
  4288. * standard. Checking for a session user match has the effect of
  4289. * letting a role self-admin only when it's conspicuously behaving
  4290. * like a user. Note that allowing self-admin under a mere SET ROLE
  4291. * would make WITH ADMIN OPTION largely irrelevant; any member could
  4292. * SET ROLE to issue the otherwise-forbidden command.
  4293. *
  4294. * Withholding self-admin in a security-restricted operation prevents
  4295. * object owners from harnessing the session user identity during
  4296. * administrative maintenance. Suppose Alice owns a database, has
  4297. * issued "GRANT alice TO bob", and runs a daily ANALYZE. Bob creates
  4298. * an alice-owned SECURITY DEFINER function that issues "REVOKE alice
  4299. * FROM carol". If he creates an expression index calling that
  4300. * function, Alice will attempt the REVOKE during each ANALYZE.
  4301. * Checking InSecurityRestrictedOperation() thwarts that attack.
  4302. *
  4303. * Withholding self-admin in SECURITY DEFINER functions makes their
  4304. * behavior independent of the calling user. There's no security or
  4305. * SQL-standard-conformance need for that restriction, though.
  4306. *
  4307. * A role cannot have actual WITH ADMIN OPTION on itself, because that
  4308. * would imply a membership loop. Therefore, we're done either way.
  4309. */
  4310. return member == GetSessionUserId() &&
  4311. !InLocalUserIdChange() && !InSecurityRestrictedOperation();
  4312. /*
  4313. * Find all the roles that member is a member of, including multi-level
  4314. * recursion. We build a list in the same way that is_member_of_role does
  4315. * to track visited and unvisited roles.
  4316. */
  4317. roles_list = list_make1_oid(member);
  4318. foreach(l, roles_list)
  4319. {
  4320. Oid memberid = lfirst_oid(l);
  4321. CatCList *memlist;
  4322. int i;
  4323. /* Find roles that memberid is directly a member of */
  4324. memlist = SearchSysCacheList1(AUTHMEMMEMROLE,
  4325. ObjectIdGetDatum(memberid));
  4326. for (i = 0; i < memlist->n_members; i++)
  4327. {
  4328. HeapTuple tup = &memlist->members[i]->tuple;
  4329. Oid otherid = ((Form_pg_auth_members) GETSTRUCT(tup))->roleid;
  4330. if (otherid == role &&
  4331. ((Form_pg_auth_members) GETSTRUCT(tup))->admin_option)
  4332. {
  4333. /* Found what we came for, so can stop searching */
  4334. result = true;
  4335. break;
  4336. }
  4337. roles_list = list_append_unique_oid(roles_list, otherid);
  4338. }
  4339. ReleaseSysCacheList(memlist);
  4340. if (result)
  4341. break;
  4342. }
  4343. list_free(roles_list);
  4344. return result;
  4345. }
  4346. /* does what it says ... */
  4347. static int
  4348. count_one_bits(AclMode mask)
  4349. {
  4350. int nbits = 0;
  4351. /* this code relies on AclMode being an unsigned type */
  4352. while (mask)
  4353. {
  4354. if (mask & 1)
  4355. nbits++;
  4356. mask >>= 1;
  4357. }
  4358. return nbits;
  4359. }
  4360. /*
  4361. * Select the effective grantor ID for a GRANT or REVOKE operation.
  4362. *
  4363. * The grantor must always be either the object owner or some role that has
  4364. * been explicitly granted grant options. This ensures that all granted
  4365. * privileges appear to flow from the object owner, and there are never
  4366. * multiple "original sources" of a privilege. Therefore, if the would-be
  4367. * grantor is a member of a role that has the needed grant options, we have
  4368. * to do the grant as that role instead.
  4369. *
  4370. * It is possible that the would-be grantor is a member of several roles
  4371. * that have different subsets of the desired grant options, but no one
  4372. * role has 'em all. In this case we pick a role with the largest number
  4373. * of desired options. Ties are broken in favor of closer ancestors.
  4374. *
  4375. * roleId: the role attempting to do the GRANT/REVOKE
  4376. * privileges: the privileges to be granted/revoked
  4377. * acl: the ACL of the object in question
  4378. * ownerId: the role owning the object in question
  4379. * *grantorId: receives the OID of the role to do the grant as
  4380. * *grantOptions: receives the grant options actually held by grantorId
  4381. *
  4382. * If no grant options exist, we set grantorId to roleId, grantOptions to 0.
  4383. */
  4384. void
  4385. select_best_grantor(Oid roleId, AclMode privileges,
  4386. const Acl *acl, Oid ownerId,
  4387. Oid *grantorId, AclMode *grantOptions)
  4388. {
  4389. AclMode needed_goptions = ACL_GRANT_OPTION_FOR(privileges);
  4390. List *roles_list;
  4391. int nrights;
  4392. ListCell *l;
  4393. /*
  4394. * The object owner is always treated as having all grant options, so if
  4395. * roleId is the owner it's easy. Also, if roleId is a superuser it's
  4396. * easy: superusers are implicitly members of every role, so they act as
  4397. * the object owner.
  4398. */
  4399. if (roleId == ownerId || superuser_arg(roleId))
  4400. {
  4401. *grantorId = ownerId;
  4402. *grantOptions = needed_goptions;
  4403. return;
  4404. }
  4405. /*
  4406. * Otherwise we have to do a careful search to see if roleId has the
  4407. * privileges of any suitable role. Note: we can hang onto the result of
  4408. * roles_has_privs_of() throughout this loop, because aclmask_direct()
  4409. * doesn't query any role memberships.
  4410. */
  4411. roles_list = roles_has_privs_of(roleId);
  4412. /* initialize candidate result as default */
  4413. *grantorId = roleId;
  4414. *grantOptions = ACL_NO_RIGHTS;
  4415. nrights = 0;
  4416. foreach(l, roles_list)
  4417. {
  4418. Oid otherrole = lfirst_oid(l);
  4419. AclMode otherprivs;
  4420. otherprivs = aclmask_direct(acl, otherrole, ownerId,
  4421. needed_goptions, ACLMASK_ALL);
  4422. if (otherprivs == needed_goptions)
  4423. {
  4424. /* Found a suitable grantor */
  4425. *grantorId = otherrole;
  4426. *grantOptions = otherprivs;
  4427. return;
  4428. }
  4429. /*
  4430. * If it has just some of the needed privileges, remember best
  4431. * candidate.
  4432. */
  4433. if (otherprivs != ACL_NO_RIGHTS)
  4434. {
  4435. int nnewrights = count_one_bits(otherprivs);
  4436. if (nnewrights > nrights)
  4437. {
  4438. *grantorId = otherrole;
  4439. *grantOptions = otherprivs;
  4440. nrights = nnewrights;
  4441. }
  4442. }
  4443. }
  4444. }
  4445. /*
  4446. * get_role_oid - Given a role name, look up the role's OID.
  4447. *
  4448. * If missing_ok is false, throw an error if role name not found. If
  4449. * true, just return InvalidOid.
  4450. */
  4451. Oid
  4452. get_role_oid(const char *rolname, bool missing_ok)
  4453. {
  4454. Oid oid;
  4455. oid = GetSysCacheOid1(AUTHNAME, Anum_pg_authid_oid,
  4456. CStringGetDatum(rolname));
  4457. if (!OidIsValid(oid) && !missing_ok)
  4458. ereport(ERROR,
  4459. (errcode(ERRCODE_UNDEFINED_OBJECT),
  4460. errmsg("role \"%s\" does not exist", rolname)));
  4461. return oid;
  4462. }
  4463. /*
  4464. * get_role_oid_or_public - As above, but return ACL_ID_PUBLIC if the
  4465. * role name is "public".
  4466. */
  4467. Oid
  4468. get_role_oid_or_public(const char *rolname)
  4469. {
  4470. if (strcmp(rolname, "public") == 0)
  4471. return ACL_ID_PUBLIC;
  4472. return get_role_oid(rolname, false);
  4473. }
  4474. /*
  4475. * Given a RoleSpec node, return the OID it corresponds to. If missing_ok is
  4476. * true, return InvalidOid if the role does not exist.
  4477. *
  4478. * PUBLIC is always disallowed here. Routines wanting to handle the PUBLIC
  4479. * case must check the case separately.
  4480. */
  4481. Oid
  4482. get_rolespec_oid(const RoleSpec *role, bool missing_ok)
  4483. {
  4484. Oid oid;
  4485. switch (role->roletype)
  4486. {
  4487. case ROLESPEC_CSTRING:
  4488. Assert(role->rolename);
  4489. oid = get_role_oid(role->rolename, missing_ok);
  4490. break;
  4491. case ROLESPEC_CURRENT_USER:
  4492. oid = GetUserId();
  4493. break;
  4494. case ROLESPEC_SESSION_USER:
  4495. oid = GetSessionUserId();
  4496. break;
  4497. case ROLESPEC_PUBLIC:
  4498. ereport(ERROR,
  4499. (errcode(ERRCODE_UNDEFINED_OBJECT),
  4500. errmsg("role \"%s\" does not exist", "public")));
  4501. oid = InvalidOid; /* make compiler happy */
  4502. break;
  4503. default:
  4504. elog(ERROR, "unexpected role type %d", role->roletype);
  4505. }
  4506. return oid;
  4507. }
  4508. /*
  4509. * Given a RoleSpec node, return the pg_authid HeapTuple it corresponds to.
  4510. * Caller must ReleaseSysCache when done with the result tuple.
  4511. */
  4512. HeapTuple
  4513. get_rolespec_tuple(const RoleSpec *role)
  4514. {
  4515. HeapTuple tuple;
  4516. switch (role->roletype)
  4517. {
  4518. case ROLESPEC_CSTRING:
  4519. Assert(role->rolename);
  4520. tuple = SearchSysCache1(AUTHNAME, CStringGetDatum(role->rolename));
  4521. if (!HeapTupleIsValid(tuple))
  4522. ereport(ERROR,
  4523. (errcode(ERRCODE_UNDEFINED_OBJECT),
  4524. errmsg("role \"%s\" does not exist", role->rolename)));
  4525. break;
  4526. case ROLESPEC_CURRENT_USER:
  4527. tuple = SearchSysCache1(AUTHOID, GetUserId());
  4528. if (!HeapTupleIsValid(tuple))
  4529. elog(ERROR, "cache lookup failed for role %u", GetUserId());
  4530. break;
  4531. case ROLESPEC_SESSION_USER:
  4532. tuple = SearchSysCache1(AUTHOID, GetSessionUserId());
  4533. if (!HeapTupleIsValid(tuple))
  4534. elog(ERROR, "cache lookup failed for role %u", GetSessionUserId());
  4535. break;
  4536. case ROLESPEC_PUBLIC:
  4537. ereport(ERROR,
  4538. (errcode(ERRCODE_UNDEFINED_OBJECT),
  4539. errmsg("role \"%s\" does not exist", "public")));
  4540. tuple = NULL; /* make compiler happy */
  4541. break;
  4542. default:
  4543. elog(ERROR, "unexpected role type %d", role->roletype);
  4544. }
  4545. return tuple;
  4546. }
  4547. /*
  4548. * Given a RoleSpec, returns a palloc'ed copy of the corresponding role's name.
  4549. */
  4550. char *
  4551. get_rolespec_name(const RoleSpec *role)
  4552. {
  4553. HeapTuple tp;
  4554. Form_pg_authid authForm;
  4555. char *rolename;
  4556. tp = get_rolespec_tuple(role);
  4557. authForm = (Form_pg_authid) GETSTRUCT(tp);
  4558. rolename = pstrdup(NameStr(authForm->rolname));
  4559. ReleaseSysCache(tp);
  4560. return rolename;
  4561. }
  4562. /*
  4563. * Given a RoleSpec, throw an error if the name is reserved, using detail_msg,
  4564. * if provided.
  4565. *
  4566. * If node is NULL, no error is thrown. If detail_msg is NULL then no detail
  4567. * message is provided.
  4568. */
  4569. void
  4570. check_rolespec_name(const RoleSpec *role, const char *detail_msg)
  4571. {
  4572. if (!role)
  4573. return;
  4574. if (role->roletype != ROLESPEC_CSTRING)
  4575. return;
  4576. if (IsReservedName(role->rolename))
  4577. {
  4578. if (detail_msg)
  4579. ereport(ERROR,
  4580. (errcode(ERRCODE_RESERVED_NAME),
  4581. errmsg("role name \"%s\" is reserved",
  4582. role->rolename),
  4583. errdetail("%s", detail_msg)));
  4584. else
  4585. ereport(ERROR,
  4586. (errcode(ERRCODE_RESERVED_NAME),
  4587. errmsg("role name \"%s\" is reserved",
  4588. role->rolename)));
  4589. }
  4590. }