oldvacacl.diff

text/plain

Filename: oldvacacl.diff
Type: text/plain
Part: 0
Message: Re: [HACKERS] VACUUM as a denial-of-service attack
*** backend/parser/gram.y.orig	Thu May 22 18:16:19 1997
--- backend/parser/gram.y	Thu May 22 18:18:22 1997
***************
*** 646,656 ****
  
  privileges:  ALL PRIVILEGES
  		{
! 		 $$ = aclmakepriv("rwaR",0);
  		}
             | ALL
  		{
! 		 $$ = aclmakepriv("rwaR",0);
  		}
             | operation_commalist {
  		$$ = $1;
--- 646,656 ----
  
  privileges:  ALL PRIVILEGES
  		{
! 		 $$ = aclmakepriv("rwaRv",0);
  		}
             | ALL
  		{
! 		 $$ = aclmakepriv("rwaRv",0);
  		}
             | operation_commalist {
  		$$ = $1;
***************
*** 681,686 ****
--- 681,689 ----
  		}
  	    | RULE {
  		$$ = ACL_MODE_RU_CHR;
+ 		}
+ 	    | VACUUM {
+ 		$$ = ACL_MODE_VA_CHR;
  		}
              ;
  
*** backend/tcop/aclchk.c.orig	Thu May 22 18:18:43 1997
--- backend/tcop/aclchk.c	Thu May 22 18:25:07 1997
***************
*** 32,37 ****
--- 32,38 ----
  #include "catalog/pg_aggregate.h"
  #include "catalog/pg_proc.h"
  #include "catalog/pg_user.h"
+ #include "catalog/pg_database.h"
  #include "utils/syscache.h"
  #include "parser/catalog_utils.h"
  #include "fmgr.h"
***************
*** 62,68 ****
    "No error.",
    "Permission denied.",
    "Table does not exist.",
!   "Must be table owner."
  };
  
  #ifdef ACLDEBUG_TRACE
--- 63,70 ----
    "No error.",
    "Permission denied.",
    "Table does not exist.",
!   "Must be table owner.",
!   "Must be database dba."
  };
  
  #ifdef ACLDEBUG_TRACE
***************
*** 514,525 ****
--- 516,537 ----
  		 NAMEDATALEN, value);
  	owner_id = ((TypeTupleForm) GETSTRUCT(htp))->typowner;
  	break;
+     case DATABASEN:
+ 	if (!HeapTupleIsValid(htp))
+ 	    elog(WARN, "pg_ownercheck: database \"%-.*s\" not found",
+ 		NAMEDATALEN, value);
+ 	owner_id = ((Form_pg_database) GETSTRUCT(htp))->datdba;
+ 	break;
      default:
  	elog(WARN, "pg_ownercheck: invalid cache id: %d",
  	     cacheid);
  	break;
      }
  	
+ #ifdef ACLDEBUG_TRACE
+     elog(DEBUG, "pg_ownercheck: user = %d owner = %d", user_id, owner_id);
+ #endif
+ 
      return(user_id == owner_id);
  }
  
*** backend/tcop/utility.c.orig	Thu May 22 18:25:23 1997
--- backend/tcop/utility.c	Thu May 22 18:33:04 1997
***************
*** 614,625 ****
--- 614,644 ----
  	break;
  	
      case T_VacuumStmt:
+ 	{
+ 	    int		aclcheck_result;
+ 	    char*	dbasename;
+ 	    VacuumStmt	*stmt = (VacuumStmt *)parsetree;
+ 
+ #ifndef NO_SECURITY
+ 	    relname = stmt->vacrel;
+ 	    if (relname != NULL) {
+ 		aclcheck_result = pg_aclcheck(relname, userName, ACL_VA);
+ 		if(aclcheck_result != ACLCHECK_OK)
+ 		    elog(WARN, "%s: %s", relname, aclcheck_error_strings[aclcheck_result]);
+ 	    } else {	/* Need to check we own the DB for a full vacuum */
+ 		dbasename = GetDatabaseName();
+ 		if (!pg_ownercheck(userName, dbasename, DATABASEN))
+ 		    elog(WARN, "%s: %s", dbasename, aclcheck_error_strings[ACLCHECK_NOT_DBA]);
+ 		}
+ #endif
+ 
  	commandTag = "VACUUM";
  	CHECK_IF_ABORTED();
  	vacuum( ((VacuumStmt *) parsetree)->vacrel,
  		((VacuumStmt *) parsetree)->verbose,
  		((VacuumStmt *) parsetree)->analyze,
  		((VacuumStmt *) parsetree)->va_spec);
+ 	}
  	break;
  
      case T_ExplainStmt:
*** backend/utils/adt/acl.c.orig	Sat May 10 21:25:18 1997
--- backend/utils/adt/acl.c	Sun May 11 22:27:58 1997
***************
*** 66,72 ****
  /*
   * 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.
--- 66,72 ----
  /*
   * aclparse
   *	Consumes and parses an ACL specification of the form:
!  *		[group|user] [A-Za-z0-9]*[+-=][rwaRv]*
   *	from string 's', ignoring any leading white space or white space
   *	between the optional id type keyword (group|user) and the actual
   *	ACL specification.
***************
*** 123,128 ****
--- 123,129 ----
  	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;
+ 	case ACL_MODE_VA_CHR: aip->ai_mode |= ACL_VA; break;
  	default:  elog(WARN, "aclparse: mode flags must use \"%s\"",
  		       ACL_MODE_STR);
  	}
***************
*** 517,524 ****
      int i;
      int l;
  
!     Assert(strlen(old_privlist)<5);
!     priv = malloc(5); /* at most "rwaR" */;
  
      if (old_privlist == NULL || old_privlist[0] == '\0') {
  	priv[0] = new_priv;
--- 518,525 ----
      int i;
      int l;
  
!     Assert(strlen(old_privlist)<(N_ACL_MODES+1));
!     priv = malloc(N_ACL_MODES+1); /* at most N_ACL_MODES */;
  
      if (old_privlist == NULL || old_privlist[0] == '\0') {
  	priv[0] = new_priv;
***************
*** 530,536 ****
      
      l = strlen(old_privlist);
  
!     if (l == 4) { /* can't add any more privileges */
  	return priv;
      }
  
--- 531,537 ----
      
      l = strlen(old_privlist);
  
!     if (l == N_ACL_MODES) { /* can't add any more privileges */
  	return priv;
      }
  
*** backend/utils/cache/syscache.c.orig	Sun May 11 12:59:32 1997
--- backend/utils/cache/syscache.c	Sun May 11 20:23:39 1997
***************
*** 45,50 ****
--- 45,51 ----
  #include "catalog/pg_operator.h"
  #include "catalog/pg_proc.h"
  #include "catalog/pg_class.h"
+ #include "catalog/pg_database.h"
  #include "catalog/pg_type.h"
  #include "catalog/pg_rewrite.h"
  #include "catalog/pg_aggregate.h"
***************
*** 315,320 ****
--- 316,330 ----
                    0,
                    0 },
  	   sizeof(FormData_pg_opclass),
+            NULL,
+            (ScanFunc) NULL   },
+     { DatabaseRelationName,               /* DATABASEN */
+ 	   1,
+   	   { Anum_pg_database_datname,
+                   0,
+                   0,
+                   0 },
+ 	   sizeof(FormData_pg_database),
             NULL,
             (ScanFunc) NULL   }
  };
*** include/utils/acl.h.orig	Thu May 22 18:33:30 1997
--- include/utils/acl.h	Thu May 22 18:43:16 1997
***************
*** 52,58 ****
  #define	ACL_RD		(1<<1)	/* read */
  #define	ACL_WR		(1<<2)	/* write (append/delete/replace) */
  #define	ACL_RU		(1<<3)	/* place rules */
! #define	N_ACL_MODES	4
  
  #define	ACL_MODECHG_ADD		1
  #define	ACL_MODECHG_DEL		2
--- 52,59 ----
  #define	ACL_RD		(1<<1)	/* read */
  #define	ACL_WR		(1<<2)	/* write (append/delete/replace) */
  #define	ACL_RU		(1<<3)	/* place rules */
! #define	ACL_VA		(1<<4)	/* vacuum */
! #define	N_ACL_MODES	5
  
  #define	ACL_MODECHG_ADD		1
  #define	ACL_MODECHG_DEL		2
***************
*** 61,67 ****
  /* change this line if you want to set the default acl permission  */
  #define	ACL_WORLD_DEFAULT	(ACL_RD)
  /* #define	ACL_WORLD_DEFAULT	(ACL_RD|ACL_WR|ACL_AP|ACL_RU) */
! #define	ACL_OWNER_DEFAULT	(ACL_RD|ACL_WR|ACL_AP|ACL_RU)
  
  /*
   * AclItem
--- 62,68 ----
  /* change this line if you want to set the default acl permission  */
  #define	ACL_WORLD_DEFAULT	(ACL_RD)
  /* #define	ACL_WORLD_DEFAULT	(ACL_RD|ACL_WR|ACL_AP|ACL_RU) */
! #define	ACL_OWNER_DEFAULT	(ACL_RD|ACL_WR|ACL_AP|ACL_RU|ACL_VA)
  
  /*
   * AclItem
***************
*** 105,121 ****
  #define	ACL_MODECHG_ADD_CHR	'+'
  #define	ACL_MODECHG_DEL_CHR	'-'
  #define	ACL_MODECHG_EQL_CHR	'='
! #define	ACL_MODE_STR		"arwR"	/* list of valid characters */
  #define	ACL_MODE_AP_CHR		'a'
  #define	ACL_MODE_RD_CHR		'r'
  #define	ACL_MODE_WR_CHR		'w'
  #define	ACL_MODE_RU_CHR		'R'
  
  /* result codes for pg_aclcheck */
  #define ACLCHECK_OK               0
  #define ACLCHECK_NO_PRIV          1
  #define ACLCHECK_NO_CLASS         2
  #define ACLCHECK_NOT_OWNER        3
  
  /* warning messages.  set these in aclchk.c. */
  extern char *aclcheck_error_strings[];
--- 106,124 ----
  #define	ACL_MODECHG_ADD_CHR	'+'
  #define	ACL_MODECHG_DEL_CHR	'-'
  #define	ACL_MODECHG_EQL_CHR	'='
! #define	ACL_MODE_STR		"arwRv"	/* list of valid characters */
  #define	ACL_MODE_AP_CHR		'a'
  #define	ACL_MODE_RD_CHR		'r'
  #define	ACL_MODE_WR_CHR		'w'
  #define	ACL_MODE_RU_CHR		'R'
+ #define ACL_MODE_VA_CHR		'v' /* If you add a mode don't forget to change N_ACL_MODES */
  
  /* result codes for pg_aclcheck */
  #define ACLCHECK_OK               0
  #define ACLCHECK_NO_PRIV          1
  #define ACLCHECK_NO_CLASS         2
  #define ACLCHECK_NOT_OWNER        3
+ #define ACLCHECK_NOT_DBA          4
  
  /* warning messages.  set these in aclchk.c. */
  extern char *aclcheck_error_strings[];
*** include/utils/syscache.h.orig	Sun May 11 13:19:12 1997
--- include/utils/syscache.h	Sun May 11 13:20:42 1997
***************
*** 59,64 ****
--- 59,65 ----
  #define	REWRITENAME	25
  #define PROSRC          26
  #define CLADEFTYPE      27
+ #define DATABASEN       28
  
  /* ----------------
   *	struct cachedesc:	information needed for a call to InitSysCache()
*** bin/psql/psqlHelp.h.orig	Thu May 22 18:43:41 1997
--- bin/psql/psqlHelp.h	Fri May 23 15:32:48 1997
***************
*** 136,142 ****
        "fetch [forward|backward] [<number>|all] [in <cursorname>];"},
    { "grant",
        "grant access control to a user or group",
!       "grant <privilege[,privilege,...]> on <rel1>[,...<reln>] to \n[public | group <group> | <username>]\n\t privilege is {ALL | SELECT | INSERT | UPDATE | DELETE | RULE}"},
    { "insert",
        "insert tuples",
        "insert into <class_name> [(<attr1>...<attrN>)]\n\t[values (<expr1>...<exprN>); |\n\tselect <expr1>,...<exprN> [from <from_clause>] [where <qual>];"},
--- 136,142 ----
        "fetch [forward|backward] [<number>|all] [in <cursorname>];"},
    { "grant",
        "grant access control to a user or group",
!       "grant <privilege[,privilege,...]> on <rel1>[,...<reln>] to \n[public | group <group> | <username>]\n\t privilege is {ALL | SELECT | INSERT | UPDATE | DELETE | RULE | VACUUM}"},
    { "insert",
        "insert tuples",
        "insert into <class_name> [(<attr1>...<attrN>)]\n\t[values (<expr1>...<exprN>); |\n\tselect <expr1>,...<exprN> [from <from_clause>] [where <qual>];"},
***************
*** 157,163 ****
        "reset {DateStyle | GEQO}"},
    { "revoke",
        "revoke access control from a user or group",
!       "revoke <privilege[,privilege,...]> on <rel1>[,...<reln>] from \n[public | group <group> | <username>]\n\t privilege is {ALL | SELECT | INSERT | UPDATE | DELETE | RULE}"},
    { "rollback",
        "abort a transaction",
        "rollback [transaction|work]"},
--- 157,163 ----
        "reset {DateStyle | GEQO}"},
    { "revoke",
        "revoke access control from a user or group",
!       "revoke <privilege[,privilege,...]> on <rel1>[,...<reln>] from \n[public | group <group> | <username>]\n\t privilege is {ALL | SELECT | INSERT | UPDATE | DELETE | RULE | VACUUM}"},
    { "rollback",
        "abort a transaction",
        "rollback [transaction|work]"},
*** man/grant.l.orig	Mon May 12 08:18:55 1997
--- man/grant.l	Mon May 12 08:20:15 1997
***************
*** 10,16 ****
  	\fBon\fR <rel1>[,...<reln>]
  	\fBto\fR [\fBpublic\fR | group <group> | <username>]
  
! 	\fBprivilege\fR is {\fBALL\fR | \fBSELECT\fR | \fBINSERT\fR | \fBUPDATE\fR | \fBDELETE\fR | \fBRULE\fR}
  .fi
  .SH DESCRIPTION
  .PP
--- 10,16 ----
  	\fBon\fR <rel1>[,...<reln>]
  	\fBto\fR [\fBpublic\fR | group <group> | <username>]
  
! 	\fBprivilege\fR is {\fBALL\fR | \fBSELECT\fR | \fBINSERT\fR | \fBUPDATE\fR | \fBDELETE\fR | \fBRULE\fR | \fBVACUUM\R}
  .fi
  .SH DESCRIPTION
  .PP
*** man/revoke.l.orig	Mon May 12 08:19:14 1997
--- man/revoke.l	Mon May 12 08:20:42 1997
***************
*** 10,16 ****
  	\fBon\fR <rel1>[,...<reln>]
  	\fBfrom\fR [\fBpublic\fR | group <group> | <username>]
  
! 	\fBprivilege\fR is {\fBALL\fR | \fBSELECT\fR | \fBINSERT\fR | \fBUPDATE\fR | \fBDELETE\fR | \fBRULE\fR}
  .fi
  .SH DESCRIPTION
  .PP
--- 10,16 ----
  	\fBon\fR <rel1>[,...<reln>]
  	\fBfrom\fR [\fBpublic\fR | group <group> | <username>]
  
! 	\fBprivilege\fR is {\fBALL\fR | \fBSELECT\fR | \fBINSERT\fR | \fBUPDATE\fR | \fBDELETE\fR | \fBRULE\fR | \fBVACUUM\R}
  .fi
  .SH DESCRIPTION
  .PP
*** man/vacuum.l.orig	Thu May 22 18:47:54 1997
--- man/vacuum.l	Thu May 22 18:56:00 1997
***************
*** 1,7 ****
  .\" This is -*-nroff-*-
  .\" XXX standard disclaimer belongs here....
  .\" $Header: /usr/local/cvsroot/postgres95/src/man/vacuum.l,v 1.4 1997/05/13 04:41:54 momjian Exp $
! .TH VACUUM SQL 11/05/95 PostgreSQL PostgreSQL
  .SH NAME
  vacuum \(em vacuum a database
  .SH SYNOPSIS
--- 1,7 ----
  .\" This is -*-nroff-*-
  .\" XXX standard disclaimer belongs here....
  .\" $Header: /usr/local/cvsroot/postgres95/src/man/vacuum.l,v 1.4 1997/05/13 04:41:54 momjian Exp $
! .TH VACUUM SQL 22/05/97 PostgreSQL PostgreSQL
  .SH NAME
  vacuum \(em vacuum a database
  .SH SYNOPSIS
***************
*** 40,44 ****
  .PP
  The purge(l) command can be used to control the archive retention
  characteristics of a given table.
  .SH "SEE ALSO"
! purge(l).
--- 40,53 ----
  .PP
  The purge(l) command can be used to control the archive retention
  characteristics of a given table.
+ .PP
+ Only the database owner (DBA) is allowed to vacuum the whole database.
+ Table vacuum rights may be granted to or revoked from individual users
+ with the
+ .BR grant(l)
+ and
+ .BR revoke(l)
+ commands.
+ 
  .SH "SEE ALSO"
! purge(l) grant(l) revoke(l).