📄 acl.c
字号:
/*------------------------------------------------------------------------- * * acl.c * Basic access control list data structures manipulation routines. * * Copyright (c) 1994, Regents of the University of California * * * IDENTIFICATION * $Header: /usr/local/cvsroot/pgsql/src/backend/utils/adt/acl.c,v 1.37.2.1 1999/08/02 05:24:49 scrappy Exp $ * *------------------------------------------------------------------------- */#include <ctype.h>#include "postgres.h"#include "catalog/catalog.h"#include "catalog/pg_shadow.h"#include "catalog/pg_type.h"#include "miscadmin.h"#include "utils/acl.h"#include "utils/memutils.h"#include "utils/syscache.h"static char *getid(char *s, char *n);static int32 aclitemeq(AclItem *a1, AclItem *a2);static int32 aclitemgt(AclItem *a1, AclItem *a2);static char *aclparse(char *s, AclItem *aip, unsigned *modechg);#define ACL_IDTYPE_GID_KEYWORD "group"#define ACL_IDTYPE_UID_KEYWORD "user"/* * getid * Consumes the first alphanumeric string (identifier) found in string * 's', ignoring any leading white space. If it finds a double quote * it returns the word inside the quotes. * * RETURNS: * the string position in 's' that points to the next non-space character * in 's', after any quotes. Also: * - loads the identifier into 'name'. (If no identifier is found, 'name' * contains an empty string). */static char *getid(char *s, char *n){ unsigned len; char *id; int in_quotes = 0; Assert(s && n); while (isspace(*s)) ++s; if (*s == '"') { in_quotes = 1; s++; } for (id = s, len = 0; isalnum(*s) || *s == '_' || in_quotes; ++len, ++s) { if (in_quotes && *s == '"') { len--; in_quotes = 0; } } if (len > sizeof(NameData)) elog(ERROR, "getid: identifier cannot be >%d characters", sizeof(NameData)); if (len > 0) memmove(n, id, len); n[len] = '\0'; while (isspace(*s)) ++s; return s;}/* * aclparse * Consumes and parses an ACL specification of the form: * [group|user] [A-Za-z0-9]*[+-=][rwaR]* * from string 's', ignoring any leading white space or white space * between the optional id type keyword (group|user) and the actual * ACL specification. * * This routine is called by the parser as well as aclitemin(), hence * the added generality. * * RETURNS: * the string position in 's' immediately following the ACL * specification. Also: * - loads the structure pointed to by 'aip' with the appropriate * UID/GID, id type identifier and mode type values. * - loads 'modechg' with the mode change flag. */static char *aclparse(char *s, AclItem *aip, unsigned *modechg){ HeapTuple htup; char name[NAMEDATALEN]; Assert(s && aip && modechg);#ifdef ACLDEBUG_TRACE printf("aclparse: input = '%s'\n", s);#endif aip->ai_idtype = ACL_IDTYPE_UID; s = getid(s, name); if (*s != ACL_MODECHG_ADD_CHR && *s != ACL_MODECHG_DEL_CHR && *s != ACL_MODECHG_EQL_CHR) { /* we just read a keyword, not a name */ if (!strcmp(name, ACL_IDTYPE_GID_KEYWORD)) aip->ai_idtype = ACL_IDTYPE_GID; else if (strcmp(name, ACL_IDTYPE_UID_KEYWORD)) elog(ERROR, "aclparse: bad keyword, must be [group|user]"); s = getid(s, name); /* move s to the name beyond the keyword */ if (name[0] == '\0') elog(ERROR, "aclparse: a name must follow the [group|user] keyword"); } if (name[0] == '\0') aip->ai_idtype = ACL_IDTYPE_WORLD; switch (*s) { case ACL_MODECHG_ADD_CHR: *modechg = ACL_MODECHG_ADD; break; case ACL_MODECHG_DEL_CHR: *modechg = ACL_MODECHG_DEL; break; case ACL_MODECHG_EQL_CHR: *modechg = ACL_MODECHG_EQL; break; default: elog(ERROR, "aclparse: mode change flag must use \"%s\"", ACL_MODECHG_STR); } aip->ai_mode = ACL_NO; while (isalpha(*++s)) { switch (*s) { case ACL_MODE_AP_CHR: aip->ai_mode |= ACL_AP; break; case ACL_MODE_RD_CHR: aip->ai_mode |= ACL_RD; break; case ACL_MODE_WR_CHR: aip->ai_mode |= ACL_WR; break; case ACL_MODE_RU_CHR: aip->ai_mode |= ACL_RU; break; default: elog(ERROR, "aclparse: mode flags must use \"%s\"", ACL_MODE_STR); } } switch (aip->ai_idtype) { case ACL_IDTYPE_UID: htup = SearchSysCacheTuple(USENAME, PointerGetDatum(name), 0, 0, 0); if (!HeapTupleIsValid(htup)) elog(ERROR, "aclparse: non-existent user \"%s\"", name); aip->ai_id = ((Form_pg_shadow) GETSTRUCT(htup))->usesysid; break; case ACL_IDTYPE_GID: aip->ai_id = get_grosysid(name); break; case ACL_IDTYPE_WORLD: aip->ai_id = ACL_ID_WORLD; break; }#ifdef ACLDEBUG_TRACE elog(DEBUG, "aclparse: correctly read [%x %d %x], modechg=%x", aip->ai_idtype, aip->ai_id, aip->ai_mode, *modechg);#endif return s;}/* * makeacl * Allocates storage for a new Acl with 'n' entries. * * RETURNS: * the new Acl */Acl *makeacl(int n){ Acl *new_acl; Size size; if (n < 0) elog(ERROR, "makeacl: invalid size: %d\n", n); size = ACL_N_SIZE(n); if (!(new_acl = (Acl *) palloc(size))) elog(ERROR, "makeacl: palloc failed on %d\n", size); MemSet((char *) new_acl, 0, size); new_acl->size = size; new_acl->ndim = 1; new_acl->flags = 0; ARR_LBOUND(new_acl)[0] = 0; ARR_DIMS(new_acl)[0] = n; return new_acl;}/* * aclitemin * Allocates storage for, and fills in, a new AclItem given a string * 's' that contains an ACL specification. See aclparse for details. * * RETURNS: * the new AclItem */AclItem *aclitemin(char *s){ unsigned modechg; AclItem *aip; if (!s) elog(ERROR, "aclitemin: null string"); aip = (AclItem *) palloc(sizeof(AclItem)); if (!aip) elog(ERROR, "aclitemin: palloc failed"); s = aclparse(s, aip, &modechg); if (modechg != ACL_MODECHG_EQL) elog(ERROR, "aclitemin: cannot accept anything but = ACLs"); while (isspace(*s)) ++s; if (*s) elog(ERROR, "aclitemin: extra garbage at end of specification"); return aip;}/* * aclitemout * Allocates storage for, and fills in, a new null-delimited string * containing a formatted ACL specification. See aclparse for details. * * RETURNS: * the new string */char *aclitemout(AclItem *aip){ char *p; char *out; HeapTuple htup; unsigned i; static AclItem default_aclitem = {ACL_ID_WORLD, ACL_IDTYPE_WORLD, ACL_WORLD_DEFAULT}; extern char *int2out(); char *tmpname; if (!aip) aip = &default_aclitem; p = out = palloc(strlen("group =arwR ") + 1 + NAMEDATALEN); if (!out) elog(ERROR, "aclitemout: palloc failed"); *p = '\0'; switch (aip->ai_idtype) { case ACL_IDTYPE_UID: htup = SearchSysCacheTuple(USESYSID, ObjectIdGetDatum(aip->ai_id), 0, 0, 0); if (!HeapTupleIsValid(htup)) { char *tmp = int2out(aip->ai_id);#ifdef NOT_USED When this elog(NOTICE) goes to the libpq client, it crashes the client because the NOTICE protocol is coming right in the middle of a request for a field value.We skip the NOTICE for now. elog(NOTICE, "aclitemout: usesysid %d not found", aip->ai_id);#endif strcat(p, tmp); pfree(tmp); } else strncat(p, (char *) &((Form_pg_shadow) GETSTRUCT(htup))->usename, sizeof(NameData)); break; case ACL_IDTYPE_GID: strcat(p, "group "); tmpname = get_groname(aip->ai_id); strncat(p, tmpname, NAMEDATALEN); break; case ACL_IDTYPE_WORLD: break; default: elog(ERROR, "aclitemout: bad ai_idtype: %d", aip->ai_idtype); break; } while (*p) ++p; *p++ = '='; for (i = 0; i < N_ACL_MODES; ++i) if ((aip->ai_mode >> i) & 01) *p++ = ACL_MODE_STR[i]; *p = '\0'; return out;}/* * aclitemeq * aclitemgt * AclItem equality and greater-than comparison routines. * Two AclItems are equal iff they are both NULL or they have the * same identifier (and identifier type). * * RETURNS: * a boolean value indicating = or > */static int32aclitemeq(AclItem *a1, AclItem *a2){ if (!a1 && !a2) return 1; if (!a1 || !a2) return 0; return a1->ai_idtype == a2->ai_idtype && a1->ai_id == a2->ai_id;}static int32aclitemgt(AclItem *a1, AclItem *a2){ if (a1 && !a2) return 1; if (!a1 || !a2)
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -