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 }