github.com/cockroachdb/cockroachdb-parser@v0.23.3-0.20240213214944-911057d40c9a/pkg/sql/privilege/privilege.go (about)

     1  // Copyright 2015 The Cockroach Authors.
     2  //
     3  // Use of this software is governed by the Business Source License
     4  // included in the file licenses/BSL.txt.
     5  //
     6  // As of the Change Date specified in that file, in accordance with
     7  // the Business Source License, use of this software will be governed
     8  // by the Apache License, Version 2.0, included in the file
     9  // licenses/APL.txt.
    10  
    11  // Package privilege outlines the basic privilege system for cockroach.
    12  package privilege
    13  
    14  import (
    15  	"bytes"
    16  	"sort"
    17  	"strings"
    18  
    19  	"github.com/cockroachdb/cockroachdb-parser/pkg/sql/pgwire/pgcode"
    20  	"github.com/cockroachdb/cockroachdb-parser/pkg/sql/pgwire/pgerror"
    21  	"github.com/cockroachdb/errors"
    22  	"github.com/cockroachdb/redact"
    23  	"github.com/cockroachdb/redact/interfaces"
    24  )
    25  
    26  // Privilege represents a privilege parsed from an Access Privilege Inquiry
    27  // Function's privilege string argument.
    28  type Privilege struct {
    29  	Kind Kind
    30  	// Each privilege Kind has an optional "grant option" flag associated with
    31  	// it. A role can only grant a privilege on an object to others if it is the
    32  	// owner of the object or if it itself holds that privilege WITH GRANT OPTION
    33  	// on the object. This replaced the CockroachDB-specific GRANT privilege.
    34  	GrantOption bool
    35  }
    36  
    37  var _ redact.SafeFormatter = Privilege{}
    38  
    39  // SafeFormat implements the redact.SafeFormatter interface.
    40  func (k Privilege) SafeFormat(s redact.SafePrinter, _ rune) {
    41  	s.Printf("[kind=%s grantOption=%t]", k.Kind, k.GrantOption)
    42  }
    43  
    44  // ObjectType represents objects that can have privileges.
    45  type ObjectType string
    46  
    47  var _ redact.SafeValue = ObjectType("")
    48  
    49  // SafeValue makes ObjectType a redact.SafeValue.
    50  func (k ObjectType) SafeValue() {}
    51  
    52  const (
    53  	// Any represents any object type.
    54  	Any ObjectType = "any"
    55  	// Database represents a database object.
    56  	Database ObjectType = "database"
    57  	// Schema represents a schema object.
    58  	Schema ObjectType = "schema"
    59  	// Table represents a table object.
    60  	Table ObjectType = "table"
    61  	// Type represents a type object.
    62  	Type ObjectType = "type"
    63  	// Sequence represents a sequence object.
    64  	Sequence ObjectType = "sequence"
    65  	// Routine represents a function or procedure object.
    66  	Routine ObjectType = "routine"
    67  	// Global represents global privileges.
    68  	Global ObjectType = "global"
    69  	// VirtualTable represents a virtual table object.
    70  	VirtualTable ObjectType = "virtual_table"
    71  	// ExternalConnection represents an external connection object.
    72  	ExternalConnection ObjectType = "external_connection"
    73  )
    74  
    75  var isDescriptorBacked = map[ObjectType]bool{
    76  	Database:           true,
    77  	Schema:             true,
    78  	Table:              true,
    79  	Type:               true,
    80  	Sequence:           true,
    81  	Routine:            true,
    82  	Global:             false,
    83  	VirtualTable:       false,
    84  	ExternalConnection: false,
    85  }
    86  
    87  // Predefined sets of privileges.
    88  var (
    89  	// AllPrivileges is populated during init.
    90  	AllPrivileges         List
    91  	ReadData              = List{SELECT}
    92  	ReadWriteData         = List{SELECT, INSERT, DELETE, UPDATE}
    93  	ReadWriteSequenceData = List{SELECT, UPDATE, USAGE}
    94  	DBPrivileges          = List{ALL, BACKUP, CONNECT, CREATE, DROP, RESTORE, ZONECONFIG}
    95  	TablePrivileges       = List{ALL, BACKUP, CHANGEFEED, CREATE, DROP, SELECT, INSERT, DELETE, UPDATE, ZONECONFIG}
    96  	SchemaPrivileges      = List{ALL, CREATE, USAGE}
    97  	TypePrivileges        = List{ALL, USAGE}
    98  	RoutinePrivileges     = List{ALL, EXECUTE}
    99  	// SequencePrivileges is appended with TablePrivileges as well. This is because
   100  	// before v22.2 we treated Sequences the same as Tables. This is to avoid making
   101  	// certain privileges unavailable after upgrade migration.
   102  	// Note that "CREATE, CHANGEFEED, INSERT, DELETE, ZONECONFIG" are no-op privileges on sequences.
   103  	SequencePrivileges = List{ALL, USAGE, SELECT, UPDATE, CREATE, CHANGEFEED, DROP, INSERT, DELETE, ZONECONFIG}
   104  	GlobalPrivileges   = List{
   105  		ALL, BACKUP, RESTORE, MODIFYCLUSTERSETTING, EXTERNALCONNECTION, VIEWACTIVITY, VIEWACTIVITYREDACTED,
   106  		VIEWCLUSTERSETTING, CANCELQUERY, NOSQLLOGIN, VIEWCLUSTERMETADATA, VIEWDEBUG, EXTERNALIOIMPLICITACCESS, VIEWJOB,
   107  		MODIFYSQLCLUSTERSETTING, REPLICATION, MANAGEVIRTUALCLUSTER, VIEWSYSTEMTABLE, CREATEROLE, CREATELOGIN, CREATEDB, CONTROLJOB,
   108  		REPAIRCLUSTERMETADATA,
   109  	}
   110  	VirtualTablePrivileges       = List{ALL, SELECT}
   111  	ExternalConnectionPrivileges = List{ALL, USAGE, DROP}
   112  )
   113  
   114  // Mask returns the bitmask for a given privilege.
   115  func (k Kind) Mask() uint64 {
   116  	return 1 << k
   117  }
   118  
   119  // IsSetIn returns true if this privilege kind is set in the supplied bitfield.
   120  func (k Kind) IsSetIn(bits uint64) bool {
   121  	return bits&k.Mask() != 0
   122  }
   123  
   124  // List is a list of privileges.
   125  type List []Kind
   126  
   127  var _ redact.SafeFormatter = List{}
   128  
   129  // SafeFormat implements the redact.SafeFormatter interface.
   130  func (pl List) SafeFormat(s interfaces.SafePrinter, _ rune) {
   131  	if s.Flag('+') {
   132  		s.SafeString("[")
   133  	}
   134  	for i, p := range pl {
   135  		if i > 0 {
   136  			s.SafeString(", ")
   137  		}
   138  		s.Print(p)
   139  	}
   140  	if s.Flag('+') {
   141  		s.SafeString("]")
   142  	}
   143  }
   144  
   145  // Len, Swap, and Less implement the Sort interface.
   146  func (pl List) Len() int {
   147  	return len(pl)
   148  }
   149  
   150  func (pl List) Swap(i, j int) {
   151  	pl[i], pl[j] = pl[j], pl[i]
   152  }
   153  
   154  func (pl List) Less(i, j int) bool {
   155  	return pl[i] < pl[j]
   156  }
   157  
   158  // names returns a list of privilege names in the same
   159  // order as "pl".
   160  func (pl List) names() []string {
   161  	ret := make([]string, len(pl))
   162  	for i, p := range pl {
   163  		ret[i] = string(p.DisplayName())
   164  	}
   165  	return ret
   166  }
   167  
   168  // keys returns a list of privilege storage keys in the same
   169  // order as "pl".
   170  func (pl List) keys() []string {
   171  	ret := make([]string, len(pl))
   172  	for i, p := range pl {
   173  		ret[i] = string(p.InternalKey())
   174  	}
   175  	return ret
   176  }
   177  
   178  // FormatNames prints out the list of display names in a buffer.
   179  // This keeps the existing order and uses ", " as separator.
   180  func (pl List) FormatNames(buf *bytes.Buffer) {
   181  	for i, p := range pl {
   182  		if i > 0 {
   183  			buf.WriteString(", ")
   184  		}
   185  		buf.WriteString(string(p.DisplayName()))
   186  	}
   187  }
   188  
   189  // SortedDisplayNames returns a list of privilege display names
   190  // in sorted order.
   191  func (pl List) SortedDisplayNames() []string {
   192  	names := pl.names()
   193  	sort.Strings(names)
   194  	return names
   195  }
   196  
   197  // SortedKeys returns a list of privilege internal keys
   198  // in sorted order.
   199  func (pl List) SortedKeys() []string {
   200  	keys := pl.keys()
   201  	sort.Strings(keys)
   202  	return keys
   203  }
   204  
   205  // ToBitField returns the bitfield representation of
   206  // a list of privileges.
   207  func (pl List) ToBitField() uint64 {
   208  	var ret uint64
   209  	for _, p := range pl {
   210  		ret |= p.Mask()
   211  	}
   212  	return ret
   213  }
   214  
   215  // Contains returns true iff the list contains the given privilege kind.
   216  func (pl List) Contains(k Kind) bool {
   217  	for _, p := range pl {
   218  		if p == k {
   219  			return true
   220  		}
   221  	}
   222  	return false
   223  }
   224  
   225  // ListFromBitField takes a bitfield of privileges and a ObjectType
   226  // returns a List. It is ordered in increasing value of privilege.Kind.
   227  func ListFromBitField(m uint64, objectType ObjectType) (List, error) {
   228  	ret := List{}
   229  
   230  	privileges, err := GetValidPrivilegesForObject(objectType)
   231  	if err != nil {
   232  		return nil, err
   233  	}
   234  
   235  	for _, p := range privileges {
   236  		if m&p.Mask() != 0 {
   237  			ret = append(ret, p)
   238  		}
   239  	}
   240  	return ret, nil
   241  }
   242  
   243  // PrivilegesFromBitFields takes a bitfield of privilege kinds, a bitfield of grant options, and an ObjectType
   244  // returns a List. It is ordered in increasing value of privilege.Kind.
   245  func PrivilegesFromBitFields(
   246  	kindBits, grantOptionBits uint64, objectType ObjectType,
   247  ) ([]Privilege, error) {
   248  	var ret []Privilege
   249  
   250  	kinds, err := GetValidPrivilegesForObject(objectType)
   251  	if err != nil {
   252  		return nil, err
   253  	}
   254  
   255  	for _, kind := range kinds {
   256  		if mask := kind.Mask(); kindBits&mask != 0 {
   257  			ret = append(ret, Privilege{
   258  				Kind:        kind,
   259  				GrantOption: grantOptionBits&mask != 0,
   260  			})
   261  		}
   262  	}
   263  	return ret, nil
   264  }
   265  
   266  // Origin indicates the origin of the privileges being parsed in
   267  // ListFromStrings.
   268  type Origin bool
   269  
   270  const (
   271  	// OriginFromUserInput indicates that the privilege name came from user
   272  	// input and should be validated to make sure it refers to a real privilege.
   273  	OriginFromUserInput Origin = false
   274  
   275  	// OriginFromSystemTable indicates that the privilege name came from a
   276  	// system table and should be ignored if it does not refer to a real
   277  	// privilege.
   278  	OriginFromSystemTable Origin = true
   279  )
   280  
   281  // ListFromStrings takes a list of internal storage keys and attempts to build a
   282  // list of Kind. Each string is converted to uppercase and is searched for
   283  // either in ByInternalKey or in ByDisplayName maps, depending on the origin. If
   284  // an entry is not found, it is either ignored or an error is raised (also
   285  // depending on the origin).
   286  func ListFromStrings(strs []string, origin Origin) (List, error) {
   287  	ret := make(List, len(strs))
   288  	for i, s := range strs {
   289  		var k Kind
   290  		switch origin {
   291  		case OriginFromSystemTable:
   292  			var ok bool
   293  			k, ok = ByInternalKey[KindInternalKey(strings.ToUpper(s))]
   294  			if !ok {
   295  				// Ignore an unknown privilege name if it came from a system table. This
   296  				// is so that it is possible to backport new privileges onto older release
   297  				// branches, without causing mixed-version compatibility issues.
   298  				continue
   299  			}
   300  
   301  		case OriginFromUserInput:
   302  			var ok bool
   303  			k, ok = ByDisplayName[KindDisplayName(strings.ToUpper(s))]
   304  			if !ok {
   305  				return nil, errors.Errorf("not a valid privilege: %q", s)
   306  			}
   307  		}
   308  		ret[i] = k
   309  	}
   310  	return ret, nil
   311  }
   312  
   313  // ValidatePrivileges returns an error if any privilege in
   314  // privileges cannot be granted on the given objectType.
   315  func ValidatePrivileges(privileges List, objectType ObjectType) error {
   316  	validPrivs, err := GetValidPrivilegesForObject(objectType)
   317  	if err != nil {
   318  		return err
   319  	}
   320  	for _, priv := range privileges {
   321  		if validPrivs.ToBitField()&priv.Mask() == 0 {
   322  			return pgerror.Newf(pgcode.InvalidGrantOperation,
   323  				"invalid privilege type %s for %s", priv.DisplayName(), objectType)
   324  		}
   325  	}
   326  
   327  	return nil
   328  }
   329  
   330  // GetValidPrivilegesForObject returns the list of valid privileges for the
   331  // specified object type.
   332  func GetValidPrivilegesForObject(objectType ObjectType) (List, error) {
   333  	switch objectType {
   334  	case Table:
   335  		return TablePrivileges, nil
   336  	case Schema:
   337  		return SchemaPrivileges, nil
   338  	case Database:
   339  		return DBPrivileges, nil
   340  	case Type:
   341  		return TypePrivileges, nil
   342  	case Sequence:
   343  		return SequencePrivileges, nil
   344  	case Any:
   345  		return AllPrivileges, nil
   346  	case Routine:
   347  		return RoutinePrivileges, nil
   348  	case Global:
   349  		return GlobalPrivileges, nil
   350  	case VirtualTable:
   351  		return VirtualTablePrivileges, nil
   352  	case ExternalConnection:
   353  		return ExternalConnectionPrivileges, nil
   354  	default:
   355  		return nil, errors.AssertionFailedf("unknown object type %s", objectType)
   356  	}
   357  }
   358  
   359  // privToACL is a map of privilege -> ACL character
   360  var privToACL = map[Kind]string{
   361  	CREATE:  "C",
   362  	SELECT:  "r",
   363  	INSERT:  "a",
   364  	DELETE:  "d",
   365  	UPDATE:  "w",
   366  	USAGE:   "U",
   367  	CONNECT: "c",
   368  	EXECUTE: "X",
   369  }
   370  
   371  // orderedPrivs is the list of privileges sorted in alphanumeric order based on the ACL character -> CUacdrwX
   372  var orderedPrivs = List{CREATE, USAGE, INSERT, CONNECT, DELETE, SELECT, UPDATE, EXECUTE}
   373  
   374  // ListToACL converts a list of privileges to a list of Postgres
   375  // ACL items.
   376  // See: https://www.postgresql.org/docs/13/ddl-priv.html#PRIVILEGE-ABBREVS-TABLE
   377  //
   378  //	for privileges and their ACL abbreviations.
   379  func (pl List) ListToACL(grantOptions List, objectType ObjectType) (string, error) {
   380  	privileges := pl
   381  	// If ALL is present, explode ALL into the underlying privileges.
   382  	if pl.Contains(ALL) {
   383  		var err error
   384  		privileges, err = GetValidPrivilegesForObject(objectType)
   385  		if err != nil {
   386  			return "", err
   387  		}
   388  		if grantOptions.Contains(ALL) {
   389  			grantOptions, err = GetValidPrivilegesForObject(objectType)
   390  			if err != nil {
   391  				return "", err
   392  			}
   393  		}
   394  	}
   395  	chars := make([]string, len(privileges))
   396  	for _, privilege := range orderedPrivs {
   397  		if _, ok := privToACL[privilege]; !ok {
   398  			return "", errors.AssertionFailedf("unknown privilege type %s", privilege.DisplayName())
   399  		}
   400  		if privileges.Contains(privilege) {
   401  			chars = append(chars, privToACL[privilege])
   402  		}
   403  		if grantOptions.Contains(privilege) {
   404  			chars = append(chars, "*")
   405  		}
   406  	}
   407  
   408  	return strings.Join(chars, ""), nil
   409  
   410  }
   411  
   412  // IsDescriptorBacked returns whether o is a descriptor backed object.
   413  // If o is not a descriptor backed object, then privileges are stored to
   414  // system.privileges.
   415  func (o ObjectType) IsDescriptorBacked() bool {
   416  	return isDescriptorBacked[o]
   417  }
   418  
   419  // Object represents an object that can have privileges. The privileges
   420  // can either live on the descriptor or in the system.privileges table.
   421  type Object interface {
   422  	// GetObjectType returns the privilege.ObjectType of the Object.
   423  	GetObjectType() ObjectType
   424  	// GetObjectTypeString returns a human-readable representation of the
   425  	// privilege.ObjectType.
   426  	// NOTE: It may not match the privilege.ObjectType directly because it may
   427  	// be more specific for some object types. For example, for functions and
   428  	// procedures it will return "function" and "procedure", respectively,
   429  	// instead of the more generic term "routine".
   430  	GetObjectTypeString() string
   431  	// GetName returns the name of the object. For example, the name of a
   432  	// table, schema or database.
   433  	GetName() string
   434  }