aclchk.c
上传用户:blenddy
上传日期:2007-01-07
资源大小:6495k
文件大小:15k
源码类别:

数据库系统

开发平台:

Unix_Linux

  1. /*-------------------------------------------------------------------------
  2.  *
  3.  * aclchk.c
  4.  *   Routines to check access control permissions.
  5.  *
  6.  * Copyright (c) 1994, Regents of the University of California
  7.  *
  8.  *
  9.  * IDENTIFICATION
  10.  *   $Header: /usr/local/cvsroot/pgsql/src/backend/catalog/aclchk.c,v 1.22.2.1 1999/08/02 05:56:53 scrappy Exp $
  11.  *
  12.  * NOTES
  13.  *   See acl.h.
  14.  *
  15.  *-------------------------------------------------------------------------
  16.  */
  17. #include "postgres.h"
  18. #include "access/heapam.h"
  19. #include "catalog/catalog.h"
  20. #include "catalog/catname.h"
  21. #include "catalog/indexing.h"
  22. #include "catalog/pg_aggregate.h"
  23. #include "catalog/pg_group.h"
  24. #include "catalog/pg_operator.h"
  25. #include "catalog/pg_proc.h"
  26. #include "catalog/pg_shadow.h"
  27. #include "catalog/pg_type.h"
  28. #include "miscadmin.h"
  29. #include "parser/parse_agg.h"
  30. #include "parser/parse_func.h"
  31. #include "utils/acl.h"
  32. #include "utils/syscache.h"
  33. static int32 aclcheck(char *relname, Acl *acl, AclId id, AclIdType idtype, AclMode mode);
  34. /*
  35.  * Enable use of user relations in place of real system catalogs.
  36.  */
  37. /*#define ACLDEBUG*/
  38. #ifdef ACLDEBUG
  39. /*
  40.  * Fool the code below into thinking that "pgacls" is pg_class.
  41.  * relname and relowner are in the same place, happily.
  42.  */
  43. #undef Anum_pg_class_relacl
  44. #define Anum_pg_class_relacl 3
  45. #undef Natts_pg_class
  46. #define Natts_pg_class 3
  47. #undef Name_pg_class
  48. #define Name_pg_class "pgacls"
  49. #undef Name_pg_group
  50. #define Name_pg_group "pggroup"
  51. #endif
  52. /* warning messages, now more explicit. */
  53. /* should correspond to the order of the ACLCHK_* result codes above. */
  54. char    *aclcheck_error_strings[] = {
  55. "No error.",
  56. "Permission denied.",
  57. "Table does not exist.",
  58. "Must be table owner."
  59. };
  60. #ifdef ACLDEBUG_TRACE
  61. static
  62. dumpacl(Acl *acl)
  63. {
  64. unsigned i;
  65. AclItem    *aip;
  66. elog(DEBUG, "acl size = %d, # acls = %d",
  67.  ACL_SIZE(acl), ACL_NUM(acl));
  68. aip = (AclItem *) ACL_DAT(acl);
  69. for (i = 0; i < ACL_NUM(acl); ++i)
  70. elog(DEBUG, " acl[%d]: %s", i, aclitemout(aip + i));
  71. }
  72. #endif
  73. /*
  74.  *
  75.  */
  76. void
  77. ChangeAcl(char *relname,
  78.   AclItem *mod_aip,
  79.   unsigned modechg)
  80. {
  81. unsigned i;
  82. Acl    *old_acl = (Acl *) NULL,
  83.    *new_acl;
  84. Relation relation;
  85. HeapTuple tuple;
  86. Datum values[Natts_pg_class];
  87. char nulls[Natts_pg_class];
  88. char replaces[Natts_pg_class];
  89. Relation idescs[Num_pg_class_indices];
  90. int free_old_acl = 0;
  91. /*
  92.  * Find the pg_class tuple matching 'relname' and extract the ACL. If
  93.  * there's no ACL, create a default using the pg_class.relowner field.
  94.  *
  95.  * We can't use the syscache here, since we need to do a heap_replace on
  96.  * the tuple we find.
  97.  */
  98. relation = heap_openr(RelationRelationName);
  99. if (!RelationIsValid(relation))
  100. elog(ERROR, "ChangeAcl: could not open '%s'??",
  101.  RelationRelationName);
  102. tuple = SearchSysCacheTuple(RELNAME,
  103. PointerGetDatum(relname),
  104. 0, 0, 0);
  105. if (!HeapTupleIsValid(tuple))
  106. {
  107. heap_close(relation);
  108. elog(ERROR, "ChangeAcl: class "%s" not found",
  109.  relname);
  110. return;
  111. }
  112. if (!heap_attisnull(tuple, Anum_pg_class_relacl))
  113. old_acl = (Acl *) heap_getattr(tuple,
  114.    Anum_pg_class_relacl,
  115.    RelationGetDescr(relation),
  116.    (bool *) NULL);
  117. if (!old_acl || ACL_NUM(old_acl) < 1)
  118. {
  119. #ifdef ACLDEBUG_TRACE
  120. elog(DEBUG, "ChangeAcl: using default ACL");
  121. #endif
  122. /* old_acl = acldefault(((Form_pg_class) GETSTRUCT(tuple))->relowner); */
  123. old_acl = acldefault(relname);
  124. free_old_acl = 1;
  125. }
  126. #ifdef ACLDEBUG_TRACE
  127. dumpacl(old_acl);
  128. #endif
  129. new_acl = aclinsert3(old_acl, mod_aip, modechg);
  130. #ifdef ACLDEBUG_TRACE
  131. dumpacl(new_acl);
  132. #endif
  133. for (i = 0; i < Natts_pg_class; ++i)
  134. {
  135. replaces[i] = ' ';
  136. nulls[i] = ' '; /* ignored if replaces[i] == ' ' anyway */
  137. values[i] = (Datum) NULL; /* ignored if replaces[i] == ' '
  138.  * anyway */
  139. }
  140. replaces[Anum_pg_class_relacl - 1] = 'r';
  141. values[Anum_pg_class_relacl - 1] = (Datum) new_acl;
  142. tuple = heap_modifytuple(tuple, relation, values, nulls, replaces);
  143. /* XXX handle index on pg_class? */
  144. setheapoverride(true);
  145. heap_replace(relation, &tuple->t_self, tuple, NULL);
  146. setheapoverride(false);
  147. /* keep the catalog indices up to date */
  148. CatalogOpenIndices(Num_pg_class_indices, Name_pg_class_indices,
  149.    idescs);
  150. CatalogIndexInsert(idescs, Num_pg_class_indices, relation, tuple);
  151. CatalogCloseIndices(Num_pg_class_indices, idescs);
  152. heap_close(relation);
  153. if (free_old_acl)
  154. pfree(old_acl);
  155. pfree(new_acl);
  156. }
  157. AclId
  158. get_grosysid(char *groname)
  159. {
  160. HeapTuple tuple;
  161. AclId id = 0;
  162. tuple = SearchSysCacheTuple(GRONAME,
  163. PointerGetDatum(groname),
  164. 0, 0, 0);
  165. if (HeapTupleIsValid(tuple))
  166. id = ((Form_pg_group) GETSTRUCT(tuple))->grosysid;
  167. else
  168. elog(ERROR, "non-existent group "%s"", groname);
  169. return id;
  170. }
  171. char *
  172. get_groname(AclId grosysid)
  173. {
  174. HeapTuple tuple;
  175. char    *name = NULL;
  176. tuple = SearchSysCacheTuple(GROSYSID,
  177. ObjectIdGetDatum(grosysid),
  178. 0, 0, 0);
  179. if (HeapTupleIsValid(tuple))
  180. name = (((Form_pg_group) GETSTRUCT(tuple))->groname).data;
  181. else
  182. elog(NOTICE, "get_groname: group %d not found", grosysid);
  183. return name;
  184. }
  185. static int32
  186. in_group(AclId uid, AclId gid)
  187. {
  188. Relation relation;
  189. HeapTuple tuple;
  190. Acl    *tmp;
  191. unsigned i,
  192. num;
  193. AclId    *aidp;
  194. int32 found = 0;
  195. relation = heap_openr(GroupRelationName);
  196. if (!RelationIsValid(relation))
  197. {
  198. elog(NOTICE, "in_group: could not open "%s"??",
  199.  GroupRelationName);
  200. return 0;
  201. }
  202. tuple = SearchSysCacheTuple(GROSYSID,
  203. ObjectIdGetDatum(gid),
  204. 0, 0, 0);
  205. if (HeapTupleIsValid(tuple) &&
  206. !heap_attisnull(tuple, Anum_pg_group_grolist))
  207. {
  208. tmp = (IdList *) heap_getattr(tuple,
  209.   Anum_pg_group_grolist,
  210.   RelationGetDescr(relation),
  211.   (bool *) NULL);
  212. /* XXX make me a function */
  213. num = IDLIST_NUM(tmp);
  214. aidp = IDLIST_DAT(tmp);
  215. for (i = 0; i < num; ++i)
  216. if (aidp[i] == uid)
  217. {
  218. found = 1;
  219. break;
  220. }
  221. }
  222. else
  223. elog(NOTICE, "in_group: group %d not found", gid);
  224. heap_close(relation);
  225. return found;
  226. }
  227. /*
  228.  * aclcheck
  229.  * Returns 1 if the 'id' of type 'idtype' has ACL entries in 'acl' to satisfy
  230.  * any one of the requirements of 'mode'.  Returns 0 otherwise.
  231.  */
  232. static int32
  233. aclcheck(char *relname, Acl *acl, AclId id, AclIdType idtype, AclMode mode)
  234. {
  235. unsigned i;
  236. AclItem    *aip,
  237.    *aidat;
  238. unsigned num,
  239. found_group;
  240. /* if no acl is found, use world default */
  241. if (!acl)
  242. acl = acldefault(relname);
  243. num = ACL_NUM(acl);
  244. aidat = ACL_DAT(acl);
  245. /*
  246.  * We'll treat the empty ACL like that, too, although this is more
  247.  * like an error (i.e., you manually blew away your ACL array) -- the
  248.  * system never creates an empty ACL.
  249.  */
  250. if (num < 1)
  251. {
  252. #if ACLDEBUG_TRACE || 1
  253. elog(DEBUG, "aclcheck: zero-length ACL, returning 1");
  254. #endif
  255. return ACLCHECK_OK;
  256. }
  257. switch (idtype)
  258. {
  259. case ACL_IDTYPE_UID:
  260. for (i = 1, aip = aidat + 1; /* skip world entry */
  261.  i < num && aip->ai_idtype == ACL_IDTYPE_UID;
  262.  ++i, ++aip)
  263. {
  264. if (aip->ai_id == id)
  265. {
  266. #ifdef ACLDEBUG_TRACE
  267. elog(DEBUG, "aclcheck: found %d/%d",
  268.  aip->ai_id, aip->ai_mode);
  269. #endif
  270. return (aip->ai_mode & mode) ? ACLCHECK_OK : ACLCHECK_NO_PRIV;
  271. }
  272. }
  273. for (found_group = 0;
  274.  i < num && aip->ai_idtype == ACL_IDTYPE_GID;
  275.  ++i, ++aip)
  276. {
  277. if (in_group(id, aip->ai_id))
  278. {
  279. if (aip->ai_mode & mode)
  280. {
  281. found_group = 1;
  282. break;
  283. }
  284. }
  285. }
  286. if (found_group)
  287. {
  288. #ifdef ACLDEBUG_TRACE
  289. elog(DEBUG, "aclcheck: all groups ok");
  290. #endif
  291. return ACLCHECK_OK;
  292. }
  293. break;
  294. case ACL_IDTYPE_GID:
  295. for (i = 1, aip = aidat + 1; /* skip world entry and
  296.  * UIDs */
  297.  i < num && aip->ai_idtype == ACL_IDTYPE_UID;
  298.  ++i, ++aip)
  299. ;
  300. for (;
  301.  i < num && aip->ai_idtype == ACL_IDTYPE_GID;
  302.  ++i, ++aip)
  303. {
  304. if (aip->ai_id == id)
  305. {
  306. #ifdef ACLDEBUG_TRACE
  307. elog(DEBUG, "aclcheck: found %d/%d",
  308.  aip->ai_id, aip->ai_mode);
  309. #endif
  310. return (aip->ai_mode & mode) ? ACLCHECK_OK : ACLCHECK_NO_PRIV;
  311. }
  312. }
  313. break;
  314. case ACL_IDTYPE_WORLD:
  315. break;
  316. default:
  317. elog(ERROR, "aclcheck: bogus ACL id type: %d", idtype);
  318. break;
  319. }
  320. #ifdef ACLDEBUG_TRACE
  321. elog(DEBUG, "aclcheck: using world=%d", aidat->ai_mode);
  322. #endif
  323. return (aidat->ai_mode & mode) ? ACLCHECK_OK : ACLCHECK_NO_PRIV;
  324. }
  325. int32
  326. pg_aclcheck(char *relname, char *usename, AclMode mode)
  327. {
  328. HeapTuple tuple;
  329. AclId id;
  330. Acl    *acl = (Acl *) NULL,
  331.    *tmp;
  332. int32 result;
  333. Relation relation;
  334. tuple = SearchSysCacheTuple(USENAME,
  335. PointerGetDatum(usename),
  336. 0, 0, 0);
  337. if (!HeapTupleIsValid(tuple))
  338. elog(ERROR, "pg_aclcheck: user "%s" not found",
  339.  usename);
  340. id = (AclId) ((Form_pg_shadow) GETSTRUCT(tuple))->usesysid;
  341. /*
  342.  * for the 'pg_database' relation, check the usecreatedb field before
  343.  * checking normal permissions
  344.  */
  345. if (strcmp(DatabaseRelationName, relname) == 0 &&
  346. (((Form_pg_shadow) GETSTRUCT(tuple))->usecreatedb))
  347. {
  348. /*
  349.  * note that even though the user can now append to the
  350.  * pg_database table, there is still additional permissions
  351.  * checking in dbcommands.c
  352.  */
  353. if ((mode & ACL_WR) || (mode & ACL_AP))
  354. return ACLCHECK_OK;
  355. }
  356. /*
  357.  * Deny anyone permission to update a system catalog unless
  358.  * pg_shadow.usecatupd is set. (This is to let superusers protect
  359.  * themselves from themselves.)
  360.  */
  361. if (((mode & ACL_WR) || (mode & ACL_AP)) &&
  362. !allowSystemTableMods && IsSystemRelationName(relname) &&
  363. !((Form_pg_shadow) GETSTRUCT(tuple))->usecatupd)
  364. {
  365. elog(DEBUG, "pg_aclcheck: catalog update to "%s": permission denied",
  366.  relname);
  367. return ACLCHECK_NO_PRIV;
  368. }
  369. /*
  370.  * Otherwise, superusers bypass all permission-checking.
  371.  */
  372. if (((Form_pg_shadow) GETSTRUCT(tuple))->usesuper)
  373. {
  374. #ifdef ACLDEBUG_TRACE
  375. elog(DEBUG, "pg_aclcheck: "%s" is superuser",
  376.  usename);
  377. #endif
  378. return ACLCHECK_OK;
  379. }
  380. #ifndef ACLDEBUG
  381. tuple = SearchSysCacheTuple(RELNAME,
  382. PointerGetDatum(relname),
  383. 0, 0, 0);
  384. if (!HeapTupleIsValid(tuple))
  385. {
  386. elog(ERROR, "pg_aclcheck: class "%s" not found",
  387.  relname);
  388. /* an elog(ERROR) kills us, so no need to return anything. */
  389. }
  390. if (!heap_attisnull(tuple, Anum_pg_class_relacl))
  391. {
  392. relation = heap_openr(RelationRelationName);
  393. tmp = (Acl *) heap_getattr(tuple,
  394.    Anum_pg_class_relacl,
  395.    RelationGetDescr(relation),
  396.    (bool *) NULL);
  397. acl = makeacl(ACL_NUM(tmp));
  398. memmove((char *) acl, (char *) tmp, ACL_SIZE(tmp));
  399. heap_close(relation);
  400. }
  401. else
  402. {
  403. /*
  404.  * if the acl is null, by default the owner can do whatever he
  405.  * wants to with it
  406.  */
  407. int4 ownerId;
  408. relation = heap_openr(RelationRelationName);
  409. ownerId = (int4) heap_getattr(tuple,
  410.   Anum_pg_class_relowner,
  411.   RelationGetDescr(relation),
  412.   (bool *) NULL);
  413. acl = aclownerdefault(relname, (AclId) ownerId);
  414. heap_close(relation);
  415. }
  416. #else
  417. { /* This is why the syscache is great... */
  418. static ScanKeyData relkey[1] = {
  419. {0, Anum_pg_class_relname, F_NAMEEQ}
  420. };
  421. relation = heap_openr(RelationRelationName);
  422. if (!RelationIsValid(relation))
  423. {
  424. elog(NOTICE, "pg_checkacl: could not open "%-.*s"??",
  425.  RelationRelationName);
  426. return ACLCHECK_NO_CLASS;
  427. }
  428. tuple = SearchSysCacheTuple(RELNAME,
  429. PointerGetDatum(relname),
  430. 0, 0, 0);
  431. if (HeapTupleIsValid(tuple) &&
  432. !heap_attisnull(tuple, Anum_pg_class_relacl))
  433. {
  434. tmp = (Acl *) heap_getattr(tuple,
  435.    Anum_pg_class_relacl,
  436.    RelationGetDescr(relation),
  437.    (bool *) NULL);
  438. acl = makeacl(ACL_NUM(tmp));
  439. memmove((char *) acl, (char *) tmp, ACL_SIZE(tmp));
  440. }
  441. heap_close(relation);
  442. }
  443. #endif
  444. result = aclcheck(relname, acl, id, (AclIdType) ACL_IDTYPE_UID, mode);
  445. if (acl)
  446. pfree(acl);
  447. return result;
  448. }
  449. int32
  450. pg_ownercheck(char *usename,
  451.   char *value,
  452.   int cacheid)
  453. {
  454. HeapTuple tuple;
  455. AclId user_id,
  456. owner_id = 0;
  457. tuple = SearchSysCacheTuple(USENAME,
  458. PointerGetDatum(usename),
  459. 0, 0, 0);
  460. if (!HeapTupleIsValid(tuple))
  461. elog(ERROR, "pg_ownercheck: user "%s" not found",
  462.  usename);
  463. user_id = (AclId) ((Form_pg_shadow) GETSTRUCT(tuple))->usesysid;
  464. /*
  465.  * Superusers bypass all permission-checking.
  466.  */
  467. if (((Form_pg_shadow) GETSTRUCT(tuple))->usesuper)
  468. {
  469. #ifdef ACLDEBUG_TRACE
  470. elog(DEBUG, "pg_ownercheck: user "%s" is superuser",
  471.  usename);
  472. #endif
  473. return 1;
  474. }
  475. tuple = SearchSysCacheTuple(cacheid, PointerGetDatum(value),
  476. 0, 0, 0);
  477. switch (cacheid)
  478. {
  479. case OPROID:
  480. if (!HeapTupleIsValid(tuple))
  481. elog(ERROR, "pg_ownercheck: operator %ld not found",
  482.  PointerGetDatum(value));
  483. owner_id = ((Form_pg_operator) GETSTRUCT(tuple))->oprowner;
  484. break;
  485. case PRONAME:
  486. if (!HeapTupleIsValid(tuple))
  487. elog(ERROR, "pg_ownercheck: function "%s" not found",
  488.  value);
  489. owner_id = ((Form_pg_proc) GETSTRUCT(tuple))->proowner;
  490. break;
  491. case RELNAME:
  492. if (!HeapTupleIsValid(tuple))
  493. elog(ERROR, "pg_ownercheck: class "%s" not found",
  494.  value);
  495. owner_id = ((Form_pg_class) GETSTRUCT(tuple))->relowner;
  496. break;
  497. case TYPNAME:
  498. if (!HeapTupleIsValid(tuple))
  499. elog(ERROR, "pg_ownercheck: type "%s" not found",
  500.  value);
  501. owner_id = ((Form_pg_type) GETSTRUCT(tuple))->typowner;
  502. break;
  503. default:
  504. elog(ERROR, "pg_ownercheck: invalid cache id: %d", cacheid);
  505. break;
  506. }
  507. return user_id == owner_id;
  508. }
  509. int32
  510. pg_func_ownercheck(char *usename,
  511.    char *funcname,
  512.    int nargs,
  513.    Oid *arglist)
  514. {
  515. HeapTuple tuple;
  516. AclId user_id,
  517. owner_id;
  518. tuple = SearchSysCacheTuple(USENAME,
  519. PointerGetDatum(usename),
  520. 0, 0, 0);
  521. if (!HeapTupleIsValid(tuple))
  522. elog(ERROR, "pg_func_ownercheck: user "%s" not found",
  523.  usename);
  524. user_id = (AclId) ((Form_pg_shadow) GETSTRUCT(tuple))->usesysid;
  525. /*
  526.  * Superusers bypass all permission-checking.
  527.  */
  528. if (((Form_pg_shadow) GETSTRUCT(tuple))->usesuper)
  529. {
  530. #ifdef ACLDEBUG_TRACE
  531. elog(DEBUG, "pg_ownercheck: user "%s" is superuser",
  532.  usename);
  533. #endif
  534. return 1;
  535. }
  536. tuple = SearchSysCacheTuple(PRONAME,
  537. PointerGetDatum(funcname),
  538. Int32GetDatum(nargs),
  539. PointerGetDatum(arglist),
  540. 0);
  541. if (!HeapTupleIsValid(tuple))
  542. func_error("pg_func_ownercheck", funcname, nargs, arglist, NULL);
  543. owner_id = ((Form_pg_proc) GETSTRUCT(tuple))->proowner;
  544. return user_id == owner_id;
  545. }
  546. int32
  547. pg_aggr_ownercheck(char *usename,
  548.    char *aggname,
  549.    Oid basetypeID)
  550. {
  551. HeapTuple tuple;
  552. AclId user_id,
  553. owner_id;
  554. tuple = SearchSysCacheTuple(USENAME,
  555. PointerGetDatum(usename),
  556. 0, 0, 0);
  557. if (!HeapTupleIsValid(tuple))
  558. elog(ERROR, "pg_aggr_ownercheck: user "%s" not found",
  559.  usename);
  560. user_id = (AclId) ((Form_pg_shadow) GETSTRUCT(tuple))->usesysid;
  561. /*
  562.  * Superusers bypass all permission-checking.
  563.  */
  564. if (((Form_pg_shadow) GETSTRUCT(tuple))->usesuper)
  565. {
  566. #ifdef ACLDEBUG_TRACE
  567. elog(DEBUG, "pg_aggr_ownercheck: user "%s" is superuser",
  568.  usename);
  569. #endif
  570. return 1;
  571. }
  572. tuple = SearchSysCacheTuple(AGGNAME,
  573. PointerGetDatum(aggname),
  574. ObjectIdGetDatum(basetypeID),
  575. 0, 0);
  576. if (!HeapTupleIsValid(tuple))
  577. agg_error("pg_aggr_ownercheck", aggname, basetypeID);
  578. owner_id = ((Form_pg_aggregate) GETSTRUCT(tuple))->aggowner;
  579. return user_id == owner_id;
  580. }