PageRenderTime 70ms CodeModel.GetById 17ms RepoModel.GetById 0ms app.codeStats 1ms

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

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