Commit e4949f9f authored by Marc G. Fournier's avatar Marc G. Fournier

From: Dan McGuirk <mcguirk@indirect.com>

Subject: [HACKERS] better access control error messages

This patch replaces the 'no such class or insufficient privilege' with
distinct error messages that tell you whether the table really doesn't
exist or whether access was denied.
parent c00c511b
...@@ -6,7 +6,7 @@ ...@@ -6,7 +6,7 @@
* *
* *
* IDENTIFICATION * IDENTIFICATION
* $Header: /cvsroot/pgsql/src/backend/commands/copy.c,v 1.21 1997/01/10 17:46:33 momjian Exp $ * $Header: /cvsroot/pgsql/src/backend/commands/copy.c,v 1.22 1997/03/12 20:47:32 scrappy Exp $
* *
*------------------------------------------------------------------------- *-------------------------------------------------------------------------
*/ */
...@@ -102,13 +102,15 @@ DoCopy(char *relname, bool binary, bool oids, bool from, bool pipe, ...@@ -102,13 +102,15 @@ DoCopy(char *relname, bool binary, bool oids, bool from, bool pipe,
Relation rel; Relation rel;
extern char *UserName; /* defined in global.c */ extern char *UserName; /* defined in global.c */
const AclMode required_access = from ? ACL_WR : ACL_RD; const AclMode required_access = from ? ACL_WR : ACL_RD;
int result;
rel = heap_openr(relname); rel = heap_openr(relname);
if (rel == NULL) elog(WARN, "COPY command failed. Class %s " if (rel == NULL) elog(WARN, "COPY command failed. Class %s "
"does not exist.", relname); "does not exist.", relname);
if (!pg_aclcheck(relname, UserName, required_access)) result = pg_aclcheck(relname, UserName, required_access);
elog(WARN, "%s %s", relname, ACL_NO_PRIV_WARNING); if(result != ACLCHECK_OK)
elog(WARN, "%s: %s", relname, aclcheck_error_strings[result]);
/* Above should not return */ /* Above should not return */
else if (!superuser() && !pipe) else if (!superuser() && !pipe)
elog(WARN, "You must have Postgres superuser privilege to do a COPY " elog(WARN, "You must have Postgres superuser privilege to do a COPY "
......
...@@ -26,7 +26,7 @@ ...@@ -26,7 +26,7 @@
* *
* *
* IDENTIFICATION * IDENTIFICATION
* $Header: /cvsroot/pgsql/src/backend/executor/execMain.c,v 1.10 1997/01/22 05:26:27 vadim Exp $ * $Header: /cvsroot/pgsql/src/backend/executor/execMain.c,v 1.11 1997/03/12 20:47:41 scrappy Exp $
* *
*------------------------------------------------------------------------- *-------------------------------------------------------------------------
*/ */
...@@ -289,7 +289,7 @@ ExecCheckPerms(CmdType operation, ...@@ -289,7 +289,7 @@ ExecCheckPerms(CmdType operation,
HeapTuple htp; HeapTuple htp;
List *lp; List *lp;
List *qvars, *tvars; List *qvars, *tvars;
int32 ok = 1; int32 ok = 1, aclcheck_result = -1;
char *opstr; char *opstr;
NameData rname; NameData rname;
char *userName; char *userName;
...@@ -317,21 +317,21 @@ ExecCheckPerms(CmdType operation, ...@@ -317,21 +317,21 @@ ExecCheckPerms(CmdType operation,
if (intMember(resultRelation, qvars) || if (intMember(resultRelation, qvars) ||
intMember(resultRelation, tvars)) { intMember(resultRelation, tvars)) {
/* result relation is scanned */ /* result relation is scanned */
ok = CHECK(ACL_RD); ok = ((aclcheck_result = CHECK(ACL_RD)) == ACLCHECK_OK);
opstr = "read"; opstr = "read";
if (!ok) if (!ok)
break; break;
} }
switch (operation) { switch (operation) {
case CMD_INSERT: case CMD_INSERT:
ok = CHECK(ACL_AP) || ok = ((aclcheck_result = CHECK(ACL_AP)) == ACLCHECK_OK) ||
CHECK(ACL_WR); ((aclcheck_result = CHECK(ACL_WR)) == ACLCHECK_OK);
opstr = "append"; opstr = "append";
break; break;
case CMD_NOTIFY: /* what does this mean?? -- jw, 1/6/94 */ case CMD_NOTIFY: /* what does this mean?? -- jw, 1/6/94 */
case CMD_DELETE: case CMD_DELETE:
case CMD_UPDATE: case CMD_UPDATE:
ok = CHECK(ACL_WR); ok = ((aclcheck_result = CHECK(ACL_WR)) == ACLCHECK_OK);
opstr = "write"; opstr = "write";
break; break;
default: default:
...@@ -340,7 +340,7 @@ ExecCheckPerms(CmdType operation, ...@@ -340,7 +340,7 @@ ExecCheckPerms(CmdType operation,
} }
} else { } else {
/* XXX NOTIFY?? */ /* XXX NOTIFY?? */
ok = CHECK(ACL_RD); ok = ((aclcheck_result = CHECK(ACL_RD)) == ACLCHECK_OK);
opstr = "read"; opstr = "read";
} }
if (!ok) if (!ok)
...@@ -352,7 +352,7 @@ ExecCheckPerms(CmdType operation, ...@@ -352,7 +352,7 @@ ExecCheckPerms(CmdType operation,
elog(WARN, "%s on \"%-.*s\": permission denied", opstr, elog(WARN, "%s on \"%-.*s\": permission denied", opstr,
NAMEDATALEN, rname.data); NAMEDATALEN, rname.data);
*/ */
elog(WARN, "%s %s", rname.data, ACL_NO_PRIV_WARNING); elog(WARN, "%s: %s", rname.data, aclcheck_error_strings[aclcheck_result]);
} }
} }
......
...@@ -8,7 +8,7 @@ ...@@ -8,7 +8,7 @@
* *
* *
* IDENTIFICATION * IDENTIFICATION
* $Header: /cvsroot/pgsql/src/backend/parser/Attic/parse_query.c,v 1.14 1997/02/14 23:02:29 momjian Exp $ * $Header: /cvsroot/pgsql/src/backend/parser/Attic/parse_query.c,v 1.15 1997/03/12 20:47:57 scrappy Exp $
* *
*------------------------------------------------------------------------- *-------------------------------------------------------------------------
*/ */
...@@ -133,7 +133,7 @@ addRangeTableEntry(ParseState *pstate, ...@@ -133,7 +133,7 @@ addRangeTableEntry(ParseState *pstate,
relation = heap_openr(relname); relation = heap_openr(relname);
if (relation == NULL) { if (relation == NULL) {
elog(WARN,"%s: %s", elog(WARN,"%s: %s",
relname, ACL_NO_PRIV_WARNING); relname, aclcheck_error_strings[ACLCHECK_NO_CLASS]);
} }
/* /*
......
...@@ -7,7 +7,7 @@ ...@@ -7,7 +7,7 @@
* *
* *
* IDENTIFICATION * IDENTIFICATION
* $Header: /cvsroot/pgsql/src/backend/tcop/Attic/aclchk.c,v 1.6 1997/01/23 19:33:31 scrappy Exp $ * $Header: /cvsroot/pgsql/src/backend/tcop/Attic/aclchk.c,v 1.7 1997/03/12 20:48:17 scrappy Exp $
* *
* NOTES * NOTES
* See acl.h. * See acl.h.
...@@ -17,7 +17,7 @@ ...@@ -17,7 +17,7 @@
#include <string.h> #include <string.h>
#include "postgres.h" #include "postgres.h"
#include "utils/acl.h" /* where declarations for this file goes */ #include "utils/acl.h" /* where declarations for this file go */
#include "access/heapam.h" #include "access/heapam.h"
#include "access/htup.h" #include "access/htup.h"
#include "access/tupmacs.h" #include "access/tupmacs.h"
...@@ -55,6 +55,15 @@ ...@@ -55,6 +55,15 @@
#define Name_pg_group "pggroup" #define Name_pg_group "pggroup"
#endif #endif
/* warning messages, now more explicit. */
/* should correspond to the order of the ACLCHK_* result codes above. */
char *aclcheck_error_strings[] = {
"No error.",
"Permission denied.",
"Table does not exist.",
"Must be table owner."
};
#ifdef ACLDEBUG_TRACE #ifdef ACLDEBUG_TRACE
static static
dumpacl(Acl *acl) dumpacl(Acl *acl)
...@@ -268,10 +277,10 @@ aclcheck(Acl *acl, AclId id, AclIdType idtype, AclMode mode) ...@@ -268,10 +277,10 @@ aclcheck(Acl *acl, AclId id, AclIdType idtype, AclMode mode)
* the system never creates an empty ACL. * the system never creates an empty ACL.
*/ */
if (num < 1) { if (num < 1) {
#ifdef ACLDEBUG_TRACE #ifdef ACLDEBUG_TRACE || 1
elog(DEBUG, "aclcheck: zero-length ACL, returning 1"); elog(DEBUG, "aclcheck: zero-length ACL, returning 1");
#endif #endif
return(1); return ACLCHECK_OK;
} }
switch (idtype) { switch (idtype) {
...@@ -284,7 +293,7 @@ aclcheck(Acl *acl, AclId id, AclIdType idtype, AclMode mode) ...@@ -284,7 +293,7 @@ aclcheck(Acl *acl, AclId id, AclIdType idtype, AclMode mode)
elog(DEBUG, "aclcheck: found %d/%d", elog(DEBUG, "aclcheck: found %d/%d",
aip->ai_id, aip->ai_mode); aip->ai_id, aip->ai_mode);
#endif #endif
return((aip->ai_mode & mode) ? 1 : 0); return((aip->ai_mode & mode) ? ACLCHECK_OK : ACLCHECK_NO_PRIV);
} }
} }
for (found_group = 0; for (found_group = 0;
...@@ -304,7 +313,7 @@ aclcheck(Acl *acl, AclId id, AclIdType idtype, AclMode mode) ...@@ -304,7 +313,7 @@ aclcheck(Acl *acl, AclId id, AclIdType idtype, AclMode mode)
elog(DEBUG, "aclcheck: found %d/%d", elog(DEBUG, "aclcheck: found %d/%d",
aip->ai_id, aip->ai_mode); aip->ai_id, aip->ai_mode);
#endif #endif
return(0); return ACLCHECK_NO_PRIV;
} }
#endif #endif
} }
...@@ -313,7 +322,7 @@ aclcheck(Acl *acl, AclId id, AclIdType idtype, AclMode mode) ...@@ -313,7 +322,7 @@ aclcheck(Acl *acl, AclId id, AclIdType idtype, AclMode mode)
#ifdef ACLDEBUG_TRACE #ifdef ACLDEBUG_TRACE
elog(DEBUG,"aclcheck: all groups ok"); elog(DEBUG,"aclcheck: all groups ok");
#endif #endif
return(1); return ACLCHECK_OK;
} }
break; break;
case ACL_IDTYPE_GID: case ACL_IDTYPE_GID:
...@@ -329,7 +338,7 @@ aclcheck(Acl *acl, AclId id, AclIdType idtype, AclMode mode) ...@@ -329,7 +338,7 @@ aclcheck(Acl *acl, AclId id, AclIdType idtype, AclMode mode)
elog(DEBUG, "aclcheck: found %d/%d", elog(DEBUG, "aclcheck: found %d/%d",
aip->ai_id, aip->ai_mode); aip->ai_id, aip->ai_mode);
#endif #endif
return((aip->ai_mode & mode) ? 1 : 0); return((aip->ai_mode & mode) ? ACLCHECK_OK : ACLCHECK_NO_PRIV);
} }
} }
break; break;
...@@ -343,7 +352,7 @@ aclcheck(Acl *acl, AclId id, AclIdType idtype, AclMode mode) ...@@ -343,7 +352,7 @@ aclcheck(Acl *acl, AclId id, AclIdType idtype, AclMode mode)
#ifdef ACLDEBUG_TRACE #ifdef ACLDEBUG_TRACE
elog(DEBUG, "aclcheck: using world=%d", aidat->ai_mode); elog(DEBUG, "aclcheck: using world=%d", aidat->ai_mode);
#endif #endif
return((aidat->ai_mode & mode) ? 1 : 0); return((aidat->ai_mode & mode) ? ACLCHECK_OK : ACLCHECK_NO_PRIV);
} }
int32 int32
...@@ -370,7 +379,7 @@ pg_aclcheck(char *relname, char *usename, AclMode mode) ...@@ -370,7 +379,7 @@ pg_aclcheck(char *relname, char *usename, AclMode mode)
pg_database table, there is still additional permissions checking pg_database table, there is still additional permissions checking
in dbcommands.c */ in dbcommands.c */
if (mode & ACL_AP) if (mode & ACL_AP)
return (1); return ACLCHECK_OK;
} }
/* /*
...@@ -383,7 +392,7 @@ pg_aclcheck(char *relname, char *usename, AclMode mode) ...@@ -383,7 +392,7 @@ pg_aclcheck(char *relname, char *usename, AclMode mode)
!((Form_pg_user) GETSTRUCT(htp))->usecatupd) { !((Form_pg_user) GETSTRUCT(htp))->usecatupd) {
elog(DEBUG, "pg_aclcheck: catalog update to \"%-.*s\": permission denied", elog(DEBUG, "pg_aclcheck: catalog update to \"%-.*s\": permission denied",
NAMEDATALEN, relname); NAMEDATALEN, relname);
return(0); return ACLCHECK_NO_PRIV;
} }
/* /*
...@@ -394,7 +403,7 @@ pg_aclcheck(char *relname, char *usename, AclMode mode) ...@@ -394,7 +403,7 @@ pg_aclcheck(char *relname, char *usename, AclMode mode)
elog(DEBUG, "pg_aclcheck: \"%-.*s\" is superuser", elog(DEBUG, "pg_aclcheck: \"%-.*s\" is superuser",
NAMEDATALEN, usename); NAMEDATALEN, usename);
#endif #endif
return(1); return ACLCHECK_OK;
} }
#ifndef ACLDEBUG #ifndef ACLDEBUG
...@@ -403,7 +412,7 @@ pg_aclcheck(char *relname, char *usename, AclMode mode) ...@@ -403,7 +412,7 @@ pg_aclcheck(char *relname, char *usename, AclMode mode)
if (!HeapTupleIsValid(htp)) { if (!HeapTupleIsValid(htp)) {
elog(WARN, "pg_aclcheck: class \"%-.*s\" not found", elog(WARN, "pg_aclcheck: class \"%-.*s\" not found",
NAMEDATALEN, relname); NAMEDATALEN, relname);
return(1); /* an elog(WARN) kills us, so no need to return anything. */
} }
if (!heap_attisnull(htp, Anum_pg_class_relacl)) { if (!heap_attisnull(htp, Anum_pg_class_relacl)) {
relation = heap_openr(RelationRelationName); relation = heap_openr(RelationRelationName);
...@@ -436,7 +445,7 @@ pg_aclcheck(char *relname, char *usename, AclMode mode) ...@@ -436,7 +445,7 @@ pg_aclcheck(char *relname, char *usename, AclMode mode)
if (!RelationIsValid(relation)) { if (!RelationIsValid(relation)) {
elog(NOTICE, "pg_checkacl: could not open \"%-.*s\"??", elog(NOTICE, "pg_checkacl: could not open \"%-.*s\"??",
RelationRelationName); RelationRelationName);
return(1); return ACLCHECK_NO_CLASS;
} }
fmgr_info(NameEqualRegProcedure, fmgr_info(NameEqualRegProcedure,
&relkey[0].sk_func, &relkey[0].sk_func,
...@@ -494,8 +503,8 @@ pg_ownercheck(char *usename, ...@@ -494,8 +503,8 @@ pg_ownercheck(char *usename,
switch (cacheid) { switch (cacheid) {
case OPROID: case OPROID:
if (!HeapTupleIsValid(htp)) if (!HeapTupleIsValid(htp))
elog(WARN, "pg_ownercheck: operator %d not found", elog(WARN, "pg_ownercheck: operator %ld not found",
(int) value); PointerGetDatum(value));
owner_id = ((OperatorTupleForm) GETSTRUCT(htp))->oprowner; owner_id = ((OperatorTupleForm) GETSTRUCT(htp))->oprowner;
break; break;
case PRONAME: case PRONAME:
......
...@@ -9,7 +9,7 @@ ...@@ -9,7 +9,7 @@
* *
* *
* IDENTIFICATION * IDENTIFICATION
* $Header: /cvsroot/pgsql/src/backend/tcop/utility.c,v 1.11 1997/01/16 14:56:21 momjian Exp $ * $Header: /cvsroot/pgsql/src/backend/tcop/utility.c,v 1.12 1997/03/12 20:48:27 scrappy Exp $
* *
*------------------------------------------------------------------------- *-------------------------------------------------------------------------
*/ */
...@@ -381,10 +381,13 @@ ProcessUtility(Node *parsetree, ...@@ -381,10 +381,13 @@ ProcessUtility(Node *parsetree,
case T_RuleStmt: /* CREATE RULE */ case T_RuleStmt: /* CREATE RULE */
{ {
RuleStmt *stmt = (RuleStmt *)parsetree; RuleStmt *stmt = (RuleStmt *)parsetree;
int aclcheck_result;
#ifndef NO_SECURITY #ifndef NO_SECURITY
relname = stmt->object->relname; relname = stmt->object->relname;
if (!pg_aclcheck(relname, userName, ACL_RU)) aclcheck_result = pg_aclcheck(relname, userName, ACL_RU);
elog(WARN, "%s %s", relname, ACL_NO_PRIV_WARNING); if(aclcheck_result != ACLCHECK_OK)
elog(WARN, "%s: %s", relname, aclcheck_error_strings[aclcheck_result]);
#endif #endif
commandTag = "CREATE"; commandTag = "CREATE";
CHECK_IF_ABORTED(); CHECK_IF_ABORTED();
...@@ -423,19 +426,21 @@ ProcessUtility(Node *parsetree, ...@@ -423,19 +426,21 @@ ProcessUtility(Node *parsetree,
relname); relname);
#ifndef NO_SECURITY #ifndef NO_SECURITY
if (!pg_ownercheck(userName, relname, RELNAME)) if (!pg_ownercheck(userName, relname, RELNAME))
elog(WARN, "you do not own class \"%s\"", elog(WARN, "%s: %s", relationName, aclcheck_error_strings[ACLCHECK_NOT_OWNER]);
relname);
#endif #endif
RemoveIndex(relname); RemoveIndex(relname);
break; break;
case RULE: case RULE:
{ {
char *rulename = stmt->name; char *rulename = stmt->name;
int aclcheck_result;
#ifndef NO_SECURITY #ifndef NO_SECURITY
relationName = RewriteGetRuleEventRel(rulename); relationName = RewriteGetRuleEventRel(rulename);
if (!pg_aclcheck(relationName, userName, ACL_RU)) aclcheck_result = pg_aclcheck(relationName, userName, ACL_RU);
elog(WARN, "%s %s", relationName, ACL_NO_PRIV_WARNING); if(aclcheck_result != ACLCHECK_OK) {
elog(WARN, "%s: %s", relationName, aclcheck_error_strings[aclcheck_result]);
}
#endif #endif
RemoveRewriteRule(rulename); RemoveRewriteRule(rulename);
} }
...@@ -457,7 +462,7 @@ ProcessUtility(Node *parsetree, ...@@ -457,7 +462,7 @@ ProcessUtility(Node *parsetree,
ruleName = MakeRetrieveViewRuleName(viewName); ruleName = MakeRetrieveViewRuleName(viewName);
relationName = RewriteGetRuleEventRel(ruleName); relationName = RewriteGetRuleEventRel(ruleName);
if (!pg_ownercheck(userName, relationName, RELNAME)) if (!pg_ownercheck(userName, relationName, RELNAME))
elog(WARN, "%s %s", relationName, ACL_NO_PRIV_WARNING); elog(WARN, "%s: %s", relationName, aclcheck_error_strings[ACLCHECK_NOT_OWNER]);
pfree(ruleName); pfree(ruleName);
#endif #endif
RemoveView(viewName); RemoveView(viewName);
......
...@@ -6,7 +6,7 @@ ...@@ -6,7 +6,7 @@
* *
* Copyright (c) 1994, Regents of the University of California * Copyright (c) 1994, Regents of the University of California
* *
* $Id: acl.h,v 1.4 1996/11/10 03:06:14 momjian Exp $ * $Id: acl.h,v 1.5 1997/03/12 20:48:48 scrappy Exp $
* *
* NOTES * NOTES
* For backward-compatability purposes we have to allow there * For backward-compatability purposes we have to allow there
...@@ -111,10 +111,14 @@ typedef ArrayType IdList; ...@@ -111,10 +111,14 @@ typedef ArrayType IdList;
#define ACL_MODE_WR_CHR 'w' #define ACL_MODE_WR_CHR 'w'
#define ACL_MODE_RU_CHR 'R' #define ACL_MODE_RU_CHR 'R'
/* we use this warning string both for non-existent tables and /* result codes for pg_aclcheck */
insufficient privilege so non-privileged users cannot ascertain whether #define ACLCHECK_OK 0
the class exists or not */ #define ACLCHECK_NO_PRIV 1
#define ACL_NO_PRIV_WARNING "Either no such class or insufficient privilege" #define ACLCHECK_NO_CLASS 2
#define ACLCHECK_NOT_OWNER 3
/* warning messages. set these in aclchk.c. */
extern char *aclcheck_error_strings[];
/* /*
* Enable ACL execution tracing and table dumps * Enable ACL execution tracing and table dumps
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment