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

数据库系统

开发平台:

Unix_Linux

  1. /*-------------------------------------------------------------------------
  2.  *
  3.  * acl.c
  4.  *   Basic access control list data structures manipulation routines.
  5.  *
  6.  * Copyright (c) 1994, Regents of the University of California
  7.  *
  8.  *
  9.  * IDENTIFICATION
  10.  *   $Header: /usr/local/cvsroot/pgsql/src/backend/utils/adt/acl.c,v 1.37.2.1 1999/08/02 05:24:49 scrappy Exp $
  11.  *
  12.  *-------------------------------------------------------------------------
  13.  */
  14. #include <ctype.h>
  15. #include "postgres.h"
  16. #include "catalog/catalog.h"
  17. #include "catalog/pg_shadow.h"
  18. #include "catalog/pg_type.h"
  19. #include "miscadmin.h"
  20. #include "utils/acl.h"
  21. #include "utils/memutils.h"
  22. #include "utils/syscache.h"
  23. static char *getid(char *s, char *n);
  24. static int32 aclitemeq(AclItem *a1, AclItem *a2);
  25. static int32 aclitemgt(AclItem *a1, AclItem *a2);
  26. static char *aclparse(char *s, AclItem *aip, unsigned *modechg);
  27. #define ACL_IDTYPE_GID_KEYWORD "group"
  28. #define ACL_IDTYPE_UID_KEYWORD "user"
  29. /*
  30.  * getid
  31.  * Consumes the first alphanumeric string (identifier) found in string
  32.  * 's', ignoring any leading white space. If it finds a double quote
  33.  * it returns the word inside the quotes.
  34.  *
  35.  * RETURNS:
  36.  * the string position in 's' that points to the next non-space character
  37.  * in 's', after any quotes.  Also:
  38.  * - loads the identifier into 'name'.  (If no identifier is found, 'name'
  39.  *   contains an empty string).
  40.  */
  41. static char *
  42. getid(char *s, char *n)
  43. {
  44. unsigned len;
  45. char    *id;
  46. int in_quotes = 0;
  47. Assert(s && n);
  48. while (isspace(*s))
  49. ++s;
  50. if (*s == '"')
  51. {
  52. in_quotes = 1;
  53. s++;
  54. }
  55. for (id = s, len = 0; isalnum(*s) || *s == '_' || in_quotes; ++len, ++s)
  56. {
  57. if (in_quotes && *s == '"')
  58. {
  59. len--;
  60. in_quotes = 0;
  61. }
  62. }
  63. if (len > sizeof(NameData))
  64. elog(ERROR, "getid: identifier cannot be >%d characters",
  65.  sizeof(NameData));
  66. if (len > 0)
  67. memmove(n, id, len);
  68. n[len] = '';
  69. while (isspace(*s))
  70. ++s;
  71. return s;
  72. }
  73. /*
  74.  * aclparse
  75.  * Consumes and parses an ACL specification of the form:
  76.  * [group|user] [A-Za-z0-9]*[+-=][rwaR]*
  77.  * from string 's', ignoring any leading white space or white space
  78.  * between the optional id type keyword (group|user) and the actual
  79.  * ACL specification.
  80.  *
  81.  * This routine is called by the parser as well as aclitemin(), hence
  82.  * the added generality.
  83.  *
  84.  * RETURNS:
  85.  * the string position in 's' immediately following the ACL
  86.  * specification. Also:
  87.  * - loads the structure pointed to by 'aip' with the appropriate
  88.  *   UID/GID, id type identifier and mode type values.
  89.  * - loads 'modechg' with the mode change flag.
  90.  */
  91. static char *
  92. aclparse(char *s, AclItem *aip, unsigned *modechg)
  93. {
  94. HeapTuple htup;
  95. char name[NAMEDATALEN];
  96. Assert(s && aip && modechg);
  97. #ifdef ACLDEBUG_TRACE
  98. printf("aclparse: input = '%s'n", s);
  99. #endif
  100. aip->ai_idtype = ACL_IDTYPE_UID;
  101. s = getid(s, name);
  102. if (*s != ACL_MODECHG_ADD_CHR &&
  103. *s != ACL_MODECHG_DEL_CHR &&
  104. *s != ACL_MODECHG_EQL_CHR)
  105. {
  106. /* we just read a keyword, not a name */
  107. if (!strcmp(name, ACL_IDTYPE_GID_KEYWORD))
  108. aip->ai_idtype = ACL_IDTYPE_GID;
  109. else if (strcmp(name, ACL_IDTYPE_UID_KEYWORD))
  110. elog(ERROR, "aclparse: bad keyword, must be [group|user]");
  111. s = getid(s, name); /* move s to the name beyond the keyword */
  112. if (name[0] == '')
  113. elog(ERROR, "aclparse: a name must follow the [group|user] keyword");
  114. }
  115. if (name[0] == '')
  116. aip->ai_idtype = ACL_IDTYPE_WORLD;
  117. switch (*s)
  118. {
  119. case ACL_MODECHG_ADD_CHR:
  120. *modechg = ACL_MODECHG_ADD;
  121. break;
  122. case ACL_MODECHG_DEL_CHR:
  123. *modechg = ACL_MODECHG_DEL;
  124. break;
  125. case ACL_MODECHG_EQL_CHR:
  126. *modechg = ACL_MODECHG_EQL;
  127. break;
  128. default:
  129. elog(ERROR, "aclparse: mode change flag must use "%s"",
  130.  ACL_MODECHG_STR);
  131. }
  132. aip->ai_mode = ACL_NO;
  133. while (isalpha(*++s))
  134. {
  135. switch (*s)
  136. {
  137. case ACL_MODE_AP_CHR:
  138. aip->ai_mode |= ACL_AP;
  139. break;
  140. case ACL_MODE_RD_CHR:
  141. aip->ai_mode |= ACL_RD;
  142. break;
  143. case ACL_MODE_WR_CHR:
  144. aip->ai_mode |= ACL_WR;
  145. break;
  146. case ACL_MODE_RU_CHR:
  147. aip->ai_mode |= ACL_RU;
  148. break;
  149. default:
  150. elog(ERROR, "aclparse: mode flags must use "%s"",
  151.  ACL_MODE_STR);
  152. }
  153. }
  154. switch (aip->ai_idtype)
  155. {
  156. case ACL_IDTYPE_UID:
  157. htup = SearchSysCacheTuple(USENAME,
  158.    PointerGetDatum(name),
  159.    0, 0, 0);
  160. if (!HeapTupleIsValid(htup))
  161. elog(ERROR, "aclparse: non-existent user "%s"", name);
  162. aip->ai_id = ((Form_pg_shadow) GETSTRUCT(htup))->usesysid;
  163. break;
  164. case ACL_IDTYPE_GID:
  165. aip->ai_id = get_grosysid(name);
  166. break;
  167. case ACL_IDTYPE_WORLD:
  168. aip->ai_id = ACL_ID_WORLD;
  169. break;
  170. }
  171. #ifdef ACLDEBUG_TRACE
  172. elog(DEBUG, "aclparse: correctly read [%x %d %x], modechg=%x",
  173.  aip->ai_idtype, aip->ai_id, aip->ai_mode, *modechg);
  174. #endif
  175. return s;
  176. }
  177. /*
  178.  * makeacl
  179.  * Allocates storage for a new Acl with 'n' entries.
  180.  *
  181.  * RETURNS:
  182.  * the new Acl
  183.  */
  184. Acl *
  185. makeacl(int n)
  186. {
  187. Acl    *new_acl;
  188. Size size;
  189. if (n < 0)
  190. elog(ERROR, "makeacl: invalid size: %dn", n);
  191. size = ACL_N_SIZE(n);
  192. if (!(new_acl = (Acl *) palloc(size)))
  193. elog(ERROR, "makeacl: palloc failed on %dn", size);
  194. MemSet((char *) new_acl, 0, size);
  195. new_acl->size = size;
  196. new_acl->ndim = 1;
  197. new_acl->flags = 0;
  198. ARR_LBOUND(new_acl)[0] = 0;
  199. ARR_DIMS(new_acl)[0] = n;
  200. return new_acl;
  201. }
  202. /*
  203.  * aclitemin
  204.  * Allocates storage for, and fills in, a new AclItem given a string
  205.  * 's' that contains an ACL specification.  See aclparse for details.
  206.  *
  207.  * RETURNS:
  208.  * the new AclItem
  209.  */
  210. AclItem    *
  211. aclitemin(char *s)
  212. {
  213. unsigned modechg;
  214. AclItem    *aip;
  215. if (!s)
  216. elog(ERROR, "aclitemin: null string");
  217. aip = (AclItem *) palloc(sizeof(AclItem));
  218. if (!aip)
  219. elog(ERROR, "aclitemin: palloc failed");
  220. s = aclparse(s, aip, &modechg);
  221. if (modechg != ACL_MODECHG_EQL)
  222. elog(ERROR, "aclitemin: cannot accept anything but = ACLs");
  223. while (isspace(*s))
  224. ++s;
  225. if (*s)
  226. elog(ERROR, "aclitemin: extra garbage at end of specification");
  227. return aip;
  228. }
  229. /*
  230.  * aclitemout
  231.  * Allocates storage for, and fills in, a new null-delimited string
  232.  * containing a formatted ACL specification.  See aclparse for details.
  233.  *
  234.  * RETURNS:
  235.  * the new string
  236.  */
  237. char *
  238. aclitemout(AclItem *aip)
  239. {
  240. char    *p;
  241. char    *out;
  242. HeapTuple htup;
  243. unsigned i;
  244. static AclItem default_aclitem = {ACL_ID_WORLD,
  245. ACL_IDTYPE_WORLD,
  246. ACL_WORLD_DEFAULT};
  247. extern char *int2out();
  248. char    *tmpname;
  249. if (!aip)
  250. aip = &default_aclitem;
  251. p = out = palloc(strlen("group =arwR ") + 1 + NAMEDATALEN);
  252. if (!out)
  253. elog(ERROR, "aclitemout: palloc failed");
  254. *p = '';
  255. switch (aip->ai_idtype)
  256. {
  257. case ACL_IDTYPE_UID:
  258. htup = SearchSysCacheTuple(USESYSID,
  259.    ObjectIdGetDatum(aip->ai_id),
  260.    0, 0, 0);
  261. if (!HeapTupleIsValid(htup))
  262. {
  263. char    *tmp = int2out(aip->ai_id);
  264. #ifdef NOT_USED
  265. When this elog(NOTICE) goes to the libpq client,
  266. it crashes the
  267. client because the NOTICE protocol is coming right in the middle
  268. of a request for a field value.We skip the NOTICE for now.
  269. elog(NOTICE, "aclitemout: usesysid %d not found",
  270.  aip->ai_id);
  271. #endif
  272. strcat(p, tmp);
  273. pfree(tmp);
  274. }
  275. else
  276. strncat(p, (char *) &((Form_pg_shadow)
  277.   GETSTRUCT(htup))->usename,
  278. sizeof(NameData));
  279. break;
  280. case ACL_IDTYPE_GID:
  281. strcat(p, "group ");
  282. tmpname = get_groname(aip->ai_id);
  283. strncat(p, tmpname, NAMEDATALEN);
  284. break;
  285. case ACL_IDTYPE_WORLD:
  286. break;
  287. default:
  288. elog(ERROR, "aclitemout: bad ai_idtype: %d", aip->ai_idtype);
  289. break;
  290. }
  291. while (*p)
  292. ++p;
  293. *p++ = '=';
  294. for (i = 0; i < N_ACL_MODES; ++i)
  295. if ((aip->ai_mode >> i) & 01)
  296. *p++ = ACL_MODE_STR[i];
  297. *p = '';
  298. return out;
  299. }
  300. /*
  301.  * aclitemeq
  302.  * aclitemgt
  303.  * AclItem equality and greater-than comparison routines.
  304.  * Two AclItems are equal iff they are both NULL or they have the
  305.  * same identifier (and identifier type).
  306.  *
  307.  * RETURNS:
  308.  * a boolean value indicating = or >
  309.  */
  310. static int32
  311. aclitemeq(AclItem *a1, AclItem *a2)
  312. {
  313. if (!a1 && !a2)
  314. return 1;
  315. if (!a1 || !a2)
  316. return 0;
  317. return a1->ai_idtype == a2->ai_idtype && a1->ai_id == a2->ai_id;
  318. }
  319. static int32
  320. aclitemgt(AclItem *a1, AclItem *a2)
  321. {
  322. if (a1 && !a2)
  323. return 1;
  324. if (!a1 || !a2)
  325. return 0;
  326. return ((a1->ai_idtype > a2->ai_idtype) ||
  327. (a1->ai_idtype == a2->ai_idtype && a1->ai_id > a2->ai_id));
  328. }
  329. Acl *
  330. aclownerdefault(char *relname, AclId ownerid)
  331. {
  332. Acl    *acl;
  333. AclItem    *aip;
  334. acl = makeacl(2);
  335. aip = ACL_DAT(acl);
  336. aip[0].ai_idtype = ACL_IDTYPE_WORLD;
  337. aip[0].ai_id = ACL_ID_WORLD;
  338. aip[0].ai_mode = IsSystemRelationName(relname) ? ACL_RD : ACL_WORLD_DEFAULT;
  339. aip[1].ai_idtype = ACL_IDTYPE_UID;
  340. aip[1].ai_id = ownerid;
  341. aip[1].ai_mode = ACL_OWNER_DEFAULT;
  342. return acl;
  343. }
  344. Acl *
  345. acldefault(char *relname)
  346. {
  347. Acl    *acl;
  348. AclItem    *aip;
  349. acl = makeacl(1);
  350. aip = ACL_DAT(acl);
  351. aip[0].ai_idtype = ACL_IDTYPE_WORLD;
  352. aip[0].ai_id = ACL_ID_WORLD;
  353. aip[0].ai_mode = IsSystemRelationName(relname) ? ACL_RD : ACL_WORLD_DEFAULT;
  354. return acl;
  355. }
  356. Acl *
  357. aclinsert3(Acl *old_acl, AclItem *mod_aip, unsigned modechg)
  358. {
  359. Acl    *new_acl;
  360. AclItem    *old_aip,
  361.    *new_aip;
  362. unsigned src,
  363. dst,
  364. num;
  365. if (!old_acl || ACL_NUM(old_acl) < 1)
  366. {
  367. new_acl = makeacl(0);
  368. return new_acl;
  369. }
  370. if (!mod_aip)
  371. {
  372. new_acl = makeacl(ACL_NUM(old_acl));
  373. memmove((char *) new_acl, (char *) old_acl, ACL_SIZE(old_acl));
  374. return new_acl;
  375. }
  376. num = ACL_NUM(old_acl);
  377. old_aip = ACL_DAT(old_acl);
  378. /*
  379.  * Search the ACL for an existing entry for 'id'.  If one exists, just
  380.  * modify the entry in-place (well, in the same position, since we
  381.  * actually return a copy); otherwise, insert the new entry in
  382.  * sort-order.
  383.  */
  384. /* find the first element not less than the element to be inserted */
  385. for (dst = 0; dst < num && aclitemgt(mod_aip, old_aip + dst); ++dst)
  386. ;
  387. if (dst < num && aclitemeq(mod_aip, old_aip + dst))
  388. {
  389. /* modify in-place */
  390. new_acl = makeacl(ACL_NUM(old_acl));
  391. memmove((char *) new_acl, (char *) old_acl, ACL_SIZE(old_acl));
  392. new_aip = ACL_DAT(new_acl);
  393. src = dst;
  394. }
  395. else
  396. {
  397. new_acl = makeacl(num + 1);
  398. new_aip = ACL_DAT(new_acl);
  399. if (dst == 0)
  400. { /* start */
  401. elog(ERROR, "aclinsert3: insertion before world ACL??");
  402. }
  403. else if (dst >= num)
  404. { /* end */
  405. memmove((char *) new_aip,
  406. (char *) old_aip,
  407. num * sizeof(AclItem));
  408. }
  409. else
  410. { /* middle */
  411. memmove((char *) new_aip,
  412. (char *) old_aip,
  413. dst * sizeof(AclItem));
  414. memmove((char *) (new_aip + dst + 1),
  415. (char *) (old_aip + dst),
  416. (num - dst) * sizeof(AclItem));
  417. }
  418. new_aip[dst].ai_id = mod_aip->ai_id;
  419. new_aip[dst].ai_idtype = mod_aip->ai_idtype;
  420. num++; /* set num to the size of new_acl */
  421. src = 0; /* world entry */
  422. }
  423. switch (modechg)
  424. {
  425. case ACL_MODECHG_ADD:
  426. new_aip[dst].ai_mode = old_aip[src].ai_mode | mod_aip->ai_mode;
  427. break;
  428. case ACL_MODECHG_DEL:
  429. new_aip[dst].ai_mode = old_aip[src].ai_mode & ~mod_aip->ai_mode;
  430. break;
  431. case ACL_MODECHG_EQL:
  432. new_aip[dst].ai_mode = mod_aip->ai_mode;
  433. break;
  434. }
  435. /*
  436.  * if the newly added entry has no permissions, delete it from the
  437.  * list.  For example, this helps in removing entries for users who no
  438.  * longer exists...
  439.  */
  440. for (dst = 1; dst < num; dst++)
  441. {
  442. if (new_aip[dst].ai_mode == 0)
  443. {
  444. int i;
  445. for (i = dst + 1; i < num; i++)
  446. {
  447. new_aip[i - 1].ai_id = new_aip[i].ai_id;
  448. new_aip[i - 1].ai_idtype = new_aip[i].ai_idtype;
  449. new_aip[i - 1].ai_mode = new_aip[i].ai_mode;
  450. }
  451. ARR_DIMS(new_acl)[0] = num - 1;
  452. /* Adjust also the array size because it is used for memmove */
  453. ARR_SIZE(new_acl) -= sizeof(AclItem);
  454. break;
  455. }
  456. }
  457. return new_acl;
  458. }
  459. /*
  460.  * aclinsert
  461.  *
  462.  */
  463. Acl *
  464. aclinsert(Acl *old_acl, AclItem *mod_aip)
  465. {
  466. return aclinsert3(old_acl, mod_aip, ACL_MODECHG_EQL);
  467. }
  468. Acl *
  469. aclremove(Acl *old_acl, AclItem *mod_aip)
  470. {
  471. Acl    *new_acl;
  472. AclItem    *old_aip,
  473.    *new_aip;
  474. unsigned dst,
  475. old_num,
  476. new_num;
  477. if (!old_acl || ACL_NUM(old_acl) < 1)
  478. {
  479. new_acl = makeacl(0);
  480. return new_acl;
  481. }
  482. if (!mod_aip)
  483. {
  484. new_acl = makeacl(ACL_NUM(old_acl));
  485. memmove((char *) new_acl, (char *) old_acl, ACL_SIZE(old_acl));
  486. return new_acl;
  487. }
  488. old_num = ACL_NUM(old_acl);
  489. old_aip = ACL_DAT(old_acl);
  490. for (dst = 0; dst < old_num && !aclitemeq(mod_aip, old_aip + dst); ++dst)
  491. ;
  492. if (dst >= old_num)
  493. { /* not found or empty */
  494. new_acl = makeacl(ACL_NUM(old_acl));
  495. memmove((char *) new_acl, (char *) old_acl, ACL_SIZE(old_acl));
  496. }
  497. else
  498. {
  499. new_num = old_num - 1;
  500. new_acl = makeacl(ACL_NUM(old_acl) - 1);
  501. new_aip = ACL_DAT(new_acl);
  502. if (dst == 0)
  503. { /* start */
  504. elog(ERROR, "aclremove: removal of the world ACL??");
  505. }
  506. else if (dst == old_num - 1)
  507. { /* end */
  508. memmove((char *) new_aip,
  509. (char *) old_aip,
  510. new_num * sizeof(AclItem));
  511. }
  512. else
  513. { /* middle */
  514. memmove((char *) new_aip,
  515. (char *) old_aip,
  516. dst * sizeof(AclItem));
  517. memmove((char *) (new_aip + dst),
  518. (char *) (old_aip + dst + 1),
  519. (new_num - dst) * sizeof(AclItem));
  520. }
  521. }
  522. return new_acl;
  523. }
  524. int32
  525. aclcontains(Acl *acl, AclItem *aip)
  526. {
  527. unsigned i,
  528. num;
  529. AclItem    *aidat;
  530. if (!acl || !aip || ((num = ACL_NUM(acl)) < 1))
  531. return 0;
  532. aidat = ACL_DAT(acl);
  533. for (i = 0; i < num; ++i)
  534. if (aclitemeq(aip, aidat + i))
  535. return 1;
  536. return 0;
  537. }
  538. /* parser support routines */
  539. /*
  540.  * aclmakepriv
  541.  *   make a acl privilege string out of an existing privilege string
  542.  * and a new privilege
  543.  *
  544.  * does not add duplicate privileges
  545.  *
  546.  */
  547. char *
  548. aclmakepriv(char *old_privlist, char new_priv)
  549. {
  550. char    *priv;
  551. int i;
  552. int l;
  553. Assert(strlen(old_privlist) < 5);
  554. priv = palloc(5); /* at most "rwaR" */ ;
  555. if (old_privlist == NULL || old_privlist[0] == '')
  556. {
  557. priv[0] = new_priv;
  558. priv[1] = '';
  559. return priv;
  560. }
  561. strcpy(priv, old_privlist);
  562. l = strlen(old_privlist);
  563. if (l == 4)
  564. { /* can't add any more privileges */
  565. return priv;
  566. }
  567. /* check to see if the new privilege is already in the old string */
  568. for (i = 0; i < l; i++)
  569. {
  570. if (priv[i] == new_priv)
  571. break;
  572. }
  573. if (i == l)
  574. { /* we really have a new privilege */
  575. priv[l] = new_priv;
  576. priv[l + 1] = '';
  577. }
  578. return priv;
  579. }
  580. /*
  581.  * aclmakeuser
  582.  *   user_type must be "A"  - all users
  583.  * "G"  - group
  584.  * "U"  - user
  585.  *
  586.  * concatentates the two strings together with a space in between
  587.  *
  588.  * this routine is used in the parser
  589.  *
  590.  */
  591. char *
  592. aclmakeuser(char *user_type, char *user)
  593. {
  594. char    *user_list;
  595. user_list = palloc(strlen(user) + 3);
  596. sprintf(user_list, "%s %s", user_type, user);
  597. return user_list;
  598. }
  599. /*
  600.  * makeAclStmt:
  601.  *   this is a helper routine called by the parser
  602.  * create a ChangeAclStmt
  603.  *   we take in the privilegs, relation_name_list, and grantee
  604.  * as well as a single character '+' or '-' to indicate grant or revoke
  605.  *
  606.  * returns a new ChangeACLStmt*
  607.  *
  608.  * this routines works by creating a old-style changle acl string and
  609.  * then calling aclparse;
  610.  */
  611. ChangeACLStmt *
  612. makeAclStmt(char *privileges, List *rel_list, char *grantee,
  613. char grant_or_revoke)
  614. {
  615. ChangeACLStmt *n = makeNode(ChangeACLStmt);
  616. char str[MAX_PARSE_BUFFER];
  617. /* see comment in pg_type.h */
  618. Assert(ACLITEMSIZE == sizeof(AclItem));
  619. n->aclitem = (AclItem *) palloc(sizeof(AclItem));
  620. /* the grantee string is "G <group_name>", "U  <user_name>", or "ALL" */
  621. if (grantee[0] == 'G') /* group permissions */
  622. {
  623. sprintf(str, "%s %c%s%c%c%s",
  624. ACL_IDTYPE_GID_KEYWORD,
  625. '"', grantee + 2, '"', grant_or_revoke, privileges);
  626. }
  627. else if (grantee[0] == 'U') /* user permission */
  628. {
  629. sprintf(str, "%s %c%s%c%c%s",
  630. ACL_IDTYPE_UID_KEYWORD,
  631. '"', grantee + 2, '"', grant_or_revoke, privileges);
  632. }
  633. else
  634. /* all permission */
  635. {
  636. sprintf(str, "%c%s",
  637. grant_or_revoke, privileges);
  638. }
  639. n->relNames = rel_list;
  640. aclparse(str, n->aclitem, (unsigned *) &n->modechg);
  641. return n;
  642. }