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

/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

Large files files are truncated, but you can click here to view the full file

  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 te…

Large files files are truncated, but you can click here to view the full file