github.com/dolthub/go-mysql-server@v0.18.0/sql/plan/revoke.go (about) 1 // Copyright 2021 Dolthub, Inc. 2 // 3 // Licensed under the Apache License, Version 2.0 (the "License"); 4 // you may not use this file except in compliance with the License. 5 // You may obtain a copy of the License at 6 // 7 // http://www.apache.org/licenses/LICENSE-2.0 8 // 9 // Unless required by applicable law or agreed to in writing, software 10 // distributed under the License is distributed on an "AS IS" BASIS, 11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 // See the License for the specific language governing permissions and 13 // limitations under the License. 14 15 package plan 16 17 import ( 18 "fmt" 19 "strings" 20 21 "github.com/dolthub/go-mysql-server/sql/mysql_db" 22 "github.com/dolthub/go-mysql-server/sql/types" 23 24 "github.com/dolthub/go-mysql-server/sql" 25 ) 26 27 // Revoke represents the statement REVOKE [privilege...] ON [item] FROM [user...]. 28 type Revoke struct { 29 Privileges []Privilege 30 ObjectType ObjectType 31 PrivilegeLevel PrivilegeLevel 32 Users []UserName 33 MySQLDb sql.Database 34 } 35 36 var _ sql.Node = (*Revoke)(nil) 37 var _ sql.Databaser = (*Revoke)(nil) 38 var _ sql.CollationCoercible = (*Revoke)(nil) 39 40 // Schema implements the interface sql.Node. 41 func (n *Revoke) Schema() sql.Schema { 42 return types.OkResultSchema 43 } 44 45 func (n *Revoke) IsReadOnly() bool { 46 return false 47 } 48 49 // String implements the interface sql.Node. 50 func (n *Revoke) String() string { 51 users := make([]string, len(n.Users)) 52 for i, user := range n.Users { 53 users[i] = user.String("") 54 } 55 return fmt.Sprintf("Revoke(On: %s, From: %s)", n.PrivilegeLevel.String(), strings.Join(users, ", ")) 56 } 57 58 // Database implements the interface sql.Databaser. 59 func (n *Revoke) Database() sql.Database { 60 return n.MySQLDb 61 } 62 63 // WithDatabase implements the interface sql.Databaser. 64 func (n *Revoke) WithDatabase(db sql.Database) (sql.Node, error) { 65 nn := *n 66 nn.MySQLDb = db 67 return &nn, nil 68 } 69 70 // Resolved implements the interface sql.Node. 71 func (n *Revoke) Resolved() bool { 72 _, ok := n.MySQLDb.(sql.UnresolvedDatabase) 73 return !ok 74 } 75 76 // Children implements the interface sql.Node. 77 func (n *Revoke) Children() []sql.Node { 78 return nil 79 } 80 81 // WithChildren implements the interface sql.Node. 82 func (n *Revoke) WithChildren(children ...sql.Node) (sql.Node, error) { 83 if len(children) != 0 { 84 return nil, sql.ErrInvalidChildrenNumber.New(n, len(children), 0) 85 } 86 return n, nil 87 } 88 89 // CheckPrivileges implements the interface sql.Node. 90 func (n *Revoke) CheckPrivileges(ctx *sql.Context, opChecker sql.PrivilegedOperationChecker) bool { 91 subject := sql.PrivilegeCheckSubject{Database: "mysql"} 92 if opChecker.UserHasPrivileges(ctx, 93 sql.NewPrivilegedOperation(subject, sql.PrivilegeType_Update)) { 94 return true 95 } 96 if n.PrivilegeLevel.Database == "*" && n.PrivilegeLevel.TableRoutine == "*" { 97 if n.Privileges[0].Type == PrivilegeType_All { 98 return opChecker.UserHasPrivileges(ctx, sql.NewPrivilegedOperation(sql.PrivilegeCheckSubject{}, 99 sql.PrivilegeType_Select, 100 sql.PrivilegeType_Insert, 101 sql.PrivilegeType_Update, 102 sql.PrivilegeType_Delete, 103 sql.PrivilegeType_Create, 104 sql.PrivilegeType_Drop, 105 sql.PrivilegeType_Reload, 106 sql.PrivilegeType_Shutdown, 107 sql.PrivilegeType_Process, 108 sql.PrivilegeType_File, 109 sql.PrivilegeType_References, 110 sql.PrivilegeType_Index, 111 sql.PrivilegeType_Alter, 112 sql.PrivilegeType_ShowDB, 113 sql.PrivilegeType_Super, 114 sql.PrivilegeType_CreateTempTable, 115 sql.PrivilegeType_LockTables, 116 sql.PrivilegeType_Execute, 117 sql.PrivilegeType_ReplicationSlave, 118 sql.PrivilegeType_ReplicationClient, 119 sql.PrivilegeType_CreateView, 120 sql.PrivilegeType_ShowView, 121 sql.PrivilegeType_CreateRoutine, 122 sql.PrivilegeType_AlterRoutine, 123 sql.PrivilegeType_CreateUser, 124 sql.PrivilegeType_Event, 125 sql.PrivilegeType_Trigger, 126 sql.PrivilegeType_CreateTablespace, 127 sql.PrivilegeType_CreateRole, 128 sql.PrivilegeType_DropRole, 129 sql.PrivilegeType_GrantOption, 130 )) 131 } 132 return opChecker.UserHasPrivileges(ctx, sql.NewPrivilegedOperation(sql.PrivilegeCheckSubject{}, 133 convertToSqlPrivilegeType(true, n.Privileges...)...)) 134 } else if n.PrivilegeLevel.Database != "*" && n.PrivilegeLevel.TableRoutine == "*" { 135 database := n.PrivilegeLevel.Database 136 if database == "" { 137 database = ctx.GetCurrentDatabase() 138 } 139 subject = sql.PrivilegeCheckSubject{Database: database} 140 141 if n.Privileges[0].Type == PrivilegeType_All { 142 return opChecker.UserHasPrivileges(ctx, sql.NewPrivilegedOperation(subject, 143 sql.PrivilegeType_Alter, 144 sql.PrivilegeType_AlterRoutine, 145 sql.PrivilegeType_Create, 146 sql.PrivilegeType_CreateRoutine, 147 sql.PrivilegeType_CreateTempTable, 148 sql.PrivilegeType_CreateView, 149 sql.PrivilegeType_Delete, 150 sql.PrivilegeType_Drop, 151 sql.PrivilegeType_Event, 152 sql.PrivilegeType_Execute, 153 sql.PrivilegeType_Index, 154 sql.PrivilegeType_Insert, 155 sql.PrivilegeType_LockTables, 156 sql.PrivilegeType_References, 157 sql.PrivilegeType_Select, 158 sql.PrivilegeType_ShowView, 159 sql.PrivilegeType_Trigger, 160 sql.PrivilegeType_Update, 161 sql.PrivilegeType_GrantOption, 162 )) 163 } 164 return opChecker.UserHasPrivileges(ctx, sql.NewPrivilegedOperation(subject, 165 convertToSqlPrivilegeType(true, n.Privileges...)...)) 166 } else { 167 //TODO: add column checks 168 subject = sql.PrivilegeCheckSubject{ 169 Database: n.PrivilegeLevel.Database, 170 Table: n.PrivilegeLevel.TableRoutine, 171 } 172 173 if n.Privileges[0].Type == PrivilegeType_All { 174 return opChecker.UserHasPrivileges(ctx, 175 sql.NewPrivilegedOperation(subject, 176 sql.PrivilegeType_Alter, 177 sql.PrivilegeType_Create, 178 sql.PrivilegeType_CreateView, 179 sql.PrivilegeType_Delete, 180 sql.PrivilegeType_Drop, 181 sql.PrivilegeType_Index, 182 sql.PrivilegeType_Insert, 183 sql.PrivilegeType_References, 184 sql.PrivilegeType_Select, 185 sql.PrivilegeType_ShowView, 186 sql.PrivilegeType_Trigger, 187 sql.PrivilegeType_Update, 188 sql.PrivilegeType_GrantOption, 189 )) 190 } 191 return opChecker.UserHasPrivileges(ctx, 192 sql.NewPrivilegedOperation(subject, 193 convertToSqlPrivilegeType(true, n.Privileges...)...)) 194 } 195 } 196 197 // CollationCoercibility implements the interface sql.CollationCoercible. 198 func (*Revoke) CollationCoercibility(ctx *sql.Context) (collation sql.CollationID, coercibility byte) { 199 return sql.Collation_binary, 7 200 } 201 202 // HandleGlobalPrivileges handles removing global privileges from a user. 203 func (n *Revoke) HandleGlobalPrivileges(user *mysql_db.User) error { 204 for i, priv := range n.Privileges { 205 if len(priv.Columns) > 0 { 206 return sql.ErrGrantRevokeIllegalPrivilege.New() 207 } 208 switch priv.Type { 209 case PrivilegeType_All: 210 // If ALL is present, then no other privileges may be provided. 211 // This should be enforced by the parser, so this is a backup check just in case 212 if i == 0 && len(n.Privileges) == 1 { 213 user.PrivilegeSet.ClearGlobal() 214 } else { 215 return sql.ErrGrantRevokeIllegalPrivilege.New() 216 } 217 case PrivilegeType_Alter: 218 user.PrivilegeSet.RemoveGlobalStatic(sql.PrivilegeType_Alter) 219 case PrivilegeType_AlterRoutine: 220 user.PrivilegeSet.RemoveGlobalStatic(sql.PrivilegeType_AlterRoutine) 221 case PrivilegeType_Create: 222 user.PrivilegeSet.RemoveGlobalStatic(sql.PrivilegeType_Create) 223 case PrivilegeType_CreateRole: 224 user.PrivilegeSet.RemoveGlobalStatic(sql.PrivilegeType_CreateRole) 225 case PrivilegeType_CreateRoutine: 226 user.PrivilegeSet.RemoveGlobalStatic(sql.PrivilegeType_CreateRoutine) 227 case PrivilegeType_CreateTablespace: 228 user.PrivilegeSet.RemoveGlobalStatic(sql.PrivilegeType_CreateTablespace) 229 case PrivilegeType_CreateTemporaryTables: 230 user.PrivilegeSet.RemoveGlobalStatic(sql.PrivilegeType_CreateTempTable) 231 case PrivilegeType_CreateUser: 232 user.PrivilegeSet.RemoveGlobalStatic(sql.PrivilegeType_CreateUser) 233 case PrivilegeType_CreateView: 234 user.PrivilegeSet.RemoveGlobalStatic(sql.PrivilegeType_CreateView) 235 case PrivilegeType_Delete: 236 user.PrivilegeSet.RemoveGlobalStatic(sql.PrivilegeType_Delete) 237 case PrivilegeType_Drop: 238 user.PrivilegeSet.RemoveGlobalStatic(sql.PrivilegeType_Drop) 239 case PrivilegeType_DropRole: 240 user.PrivilegeSet.RemoveGlobalStatic(sql.PrivilegeType_DropRole) 241 case PrivilegeType_Event: 242 user.PrivilegeSet.RemoveGlobalStatic(sql.PrivilegeType_Event) 243 case PrivilegeType_Execute: 244 user.PrivilegeSet.RemoveGlobalStatic(sql.PrivilegeType_Execute) 245 case PrivilegeType_File: 246 user.PrivilegeSet.RemoveGlobalStatic(sql.PrivilegeType_File) 247 case PrivilegeType_GrantOption: 248 user.PrivilegeSet.RemoveGlobalStatic(sql.PrivilegeType_GrantOption) 249 case PrivilegeType_Index: 250 user.PrivilegeSet.RemoveGlobalStatic(sql.PrivilegeType_Index) 251 case PrivilegeType_Insert: 252 user.PrivilegeSet.RemoveGlobalStatic(sql.PrivilegeType_Insert) 253 case PrivilegeType_LockTables: 254 user.PrivilegeSet.RemoveGlobalStatic(sql.PrivilegeType_LockTables) 255 case PrivilegeType_Process: 256 user.PrivilegeSet.RemoveGlobalStatic(sql.PrivilegeType_Process) 257 case PrivilegeType_References: 258 user.PrivilegeSet.RemoveGlobalStatic(sql.PrivilegeType_References) 259 case PrivilegeType_Reload: 260 user.PrivilegeSet.RemoveGlobalStatic(sql.PrivilegeType_Reload) 261 case PrivilegeType_ReplicationClient: 262 user.PrivilegeSet.RemoveGlobalStatic(sql.PrivilegeType_ReplicationClient) 263 case PrivilegeType_ReplicationSlave: 264 user.PrivilegeSet.RemoveGlobalStatic(sql.PrivilegeType_ReplicationSlave) 265 case PrivilegeType_Select: 266 user.PrivilegeSet.RemoveGlobalStatic(sql.PrivilegeType_Select) 267 case PrivilegeType_ShowDatabases: 268 user.PrivilegeSet.RemoveGlobalStatic(sql.PrivilegeType_ShowDB) 269 case PrivilegeType_ShowView: 270 user.PrivilegeSet.RemoveGlobalStatic(sql.PrivilegeType_ShowView) 271 case PrivilegeType_Shutdown: 272 user.PrivilegeSet.RemoveGlobalStatic(sql.PrivilegeType_Shutdown) 273 case PrivilegeType_Super: 274 user.PrivilegeSet.RemoveGlobalStatic(sql.PrivilegeType_Super) 275 case PrivilegeType_Trigger: 276 user.PrivilegeSet.RemoveGlobalStatic(sql.PrivilegeType_Trigger) 277 case PrivilegeType_Update: 278 user.PrivilegeSet.RemoveGlobalStatic(sql.PrivilegeType_Update) 279 case PrivilegeType_Usage: 280 // Usage is equal to no privilege 281 case PrivilegeType_Dynamic: 282 if !priv.IsValidDynamic() { 283 return fmt.Errorf(`REVOKE does not yet support the dynamic privilege: "%s"`, priv.Dynamic) 284 } 285 user.PrivilegeSet.RemoveGlobalDynamic(priv.Dynamic) 286 default: 287 return sql.ErrGrantRevokeIllegalPrivilege.New() 288 } 289 } 290 return nil 291 } 292 293 // HandleDatabasePrivileges handles removing database privileges from a user. 294 func (n *Revoke) HandleDatabasePrivileges(user *mysql_db.User, dbName string) error { 295 for i, priv := range n.Privileges { 296 if len(priv.Columns) > 0 { 297 return sql.ErrGrantRevokeIllegalPrivilege.New() 298 } 299 switch priv.Type { 300 case PrivilegeType_All: 301 // If ALL is present, then no other privileges may be provided. 302 // This should be enforced by the parser, so this is a backup check just in case 303 if i == 0 && len(n.Privileges) == 1 { 304 user.PrivilegeSet.ClearDatabase(dbName) 305 } else { 306 return sql.ErrGrantRevokeIllegalPrivilege.New() 307 } 308 case PrivilegeType_Alter: 309 user.PrivilegeSet.RemoveDatabase(dbName, sql.PrivilegeType_Alter) 310 case PrivilegeType_AlterRoutine: 311 user.PrivilegeSet.RemoveDatabase(dbName, sql.PrivilegeType_AlterRoutine) 312 case PrivilegeType_Create: 313 user.PrivilegeSet.RemoveDatabase(dbName, sql.PrivilegeType_Create) 314 case PrivilegeType_CreateRoutine: 315 user.PrivilegeSet.RemoveDatabase(dbName, sql.PrivilegeType_CreateRoutine) 316 case PrivilegeType_CreateTemporaryTables: 317 user.PrivilegeSet.RemoveDatabase(dbName, sql.PrivilegeType_CreateTempTable) 318 case PrivilegeType_CreateView: 319 user.PrivilegeSet.RemoveDatabase(dbName, sql.PrivilegeType_CreateView) 320 case PrivilegeType_Delete: 321 user.PrivilegeSet.RemoveDatabase(dbName, sql.PrivilegeType_Delete) 322 case PrivilegeType_Drop: 323 user.PrivilegeSet.RemoveDatabase(dbName, sql.PrivilegeType_Drop) 324 case PrivilegeType_Event: 325 user.PrivilegeSet.RemoveDatabase(dbName, sql.PrivilegeType_Event) 326 case PrivilegeType_Execute: 327 user.PrivilegeSet.RemoveDatabase(dbName, sql.PrivilegeType_Execute) 328 case PrivilegeType_GrantOption: 329 user.PrivilegeSet.RemoveDatabase(dbName, sql.PrivilegeType_GrantOption) 330 case PrivilegeType_Index: 331 user.PrivilegeSet.RemoveDatabase(dbName, sql.PrivilegeType_Index) 332 case PrivilegeType_Insert: 333 user.PrivilegeSet.RemoveDatabase(dbName, sql.PrivilegeType_Insert) 334 case PrivilegeType_LockTables: 335 user.PrivilegeSet.RemoveDatabase(dbName, sql.PrivilegeType_LockTables) 336 case PrivilegeType_References: 337 user.PrivilegeSet.RemoveDatabase(dbName, sql.PrivilegeType_References) 338 case PrivilegeType_Select: 339 user.PrivilegeSet.RemoveDatabase(dbName, sql.PrivilegeType_Select) 340 case PrivilegeType_ShowView: 341 user.PrivilegeSet.RemoveDatabase(dbName, sql.PrivilegeType_ShowView) 342 case PrivilegeType_Trigger: 343 user.PrivilegeSet.RemoveDatabase(dbName, sql.PrivilegeType_Trigger) 344 case PrivilegeType_Update: 345 user.PrivilegeSet.RemoveDatabase(dbName, sql.PrivilegeType_Update) 346 case PrivilegeType_Usage: 347 // Usage is equal to no privilege 348 case PrivilegeType_Dynamic: 349 return sql.ErrGrantRevokeIllegalPrivilegeWithMessage.New( 350 "dynamic privileges may only operate at a global scope") 351 default: 352 return sql.ErrGrantRevokeIllegalPrivilege.New() 353 } 354 } 355 return nil 356 } 357 358 // HandleTablePrivileges handles removing table privileges from a user. 359 func (n *Revoke) HandleTablePrivileges(user *mysql_db.User, dbName string, tblName string) error { 360 for i, priv := range n.Privileges { 361 if len(priv.Columns) > 0 { 362 return fmt.Errorf("GRANT has not yet implemented column privileges") 363 } 364 switch priv.Type { 365 case PrivilegeType_All: 366 // If ALL is present, then no other privileges may be provided. 367 // This should be enforced by the parser, so this is a backup check just in case 368 if i == 0 && len(n.Privileges) == 1 { 369 user.PrivilegeSet.ClearTable(dbName, tblName) 370 } else { 371 return sql.ErrGrantRevokeIllegalPrivilege.New() 372 } 373 case PrivilegeType_Alter: 374 user.PrivilegeSet.RemoveTable(dbName, tblName, sql.PrivilegeType_Alter) 375 case PrivilegeType_Create: 376 user.PrivilegeSet.RemoveTable(dbName, tblName, sql.PrivilegeType_Create) 377 case PrivilegeType_CreateView: 378 user.PrivilegeSet.RemoveTable(dbName, tblName, sql.PrivilegeType_CreateView) 379 case PrivilegeType_Delete: 380 user.PrivilegeSet.RemoveTable(dbName, tblName, sql.PrivilegeType_Delete) 381 case PrivilegeType_Drop: 382 user.PrivilegeSet.RemoveTable(dbName, tblName, sql.PrivilegeType_Drop) 383 case PrivilegeType_GrantOption: 384 user.PrivilegeSet.RemoveTable(dbName, tblName, sql.PrivilegeType_GrantOption) 385 case PrivilegeType_Index: 386 user.PrivilegeSet.RemoveTable(dbName, tblName, sql.PrivilegeType_Index) 387 case PrivilegeType_Insert: 388 user.PrivilegeSet.RemoveTable(dbName, tblName, sql.PrivilegeType_Insert) 389 case PrivilegeType_References: 390 user.PrivilegeSet.RemoveTable(dbName, tblName, sql.PrivilegeType_References) 391 case PrivilegeType_Select: 392 user.PrivilegeSet.RemoveTable(dbName, tblName, sql.PrivilegeType_Select) 393 case PrivilegeType_ShowView: 394 user.PrivilegeSet.RemoveTable(dbName, tblName, sql.PrivilegeType_ShowView) 395 case PrivilegeType_Trigger: 396 user.PrivilegeSet.RemoveTable(dbName, tblName, sql.PrivilegeType_Trigger) 397 case PrivilegeType_Update: 398 user.PrivilegeSet.RemoveTable(dbName, tblName, sql.PrivilegeType_Update) 399 case PrivilegeType_Usage: 400 // Usage is equal to no privilege 401 case PrivilegeType_Dynamic: 402 return sql.ErrGrantRevokeIllegalPrivilegeWithMessage.New( 403 "dynamic privileges may only operate at a global scope") 404 default: 405 return sql.ErrGrantRevokeIllegalPrivilege.New() 406 } 407 } 408 return nil 409 } 410 411 func (n *Revoke) HandleRoutinePrivileges(user *mysql_db.User, dbName string, routineName string, isProcedureType bool) error { 412 for _, priv := range n.Privileges { 413 switch priv.Type { 414 case PrivilegeType_AlterRoutine: 415 user.PrivilegeSet.RemoveRoutine(dbName, routineName, isProcedureType, sql.PrivilegeType_AlterRoutine) 416 case PrivilegeType_Execute: 417 user.PrivilegeSet.RemoveRoutine(dbName, routineName, isProcedureType, sql.PrivilegeType_Execute) 418 case PrivilegeType_GrantOption: 419 user.PrivilegeSet.RemoveRoutine(dbName, routineName, isProcedureType, sql.PrivilegeType_GrantOption) 420 default: 421 return sql.ErrGrantRevokeIllegalPrivilege.New() 422 } 423 } 424 return nil 425 } 426 427 // RevokeAll represents the statement REVOKE ALL PRIVILEGES. 428 type RevokeAll struct { 429 Users []UserName 430 } 431 432 var _ sql.Node = (*RevokeAll)(nil) 433 var _ sql.CollationCoercible = (*RevokeAll)(nil) 434 435 // NewRevokeAll returns a new RevokeAll node. 436 func NewRevokeAll(users []UserName) *RevokeAll { 437 return &RevokeAll{ 438 Users: users, 439 } 440 } 441 442 // Schema implements the interface sql.Node. 443 func (n *RevokeAll) Schema() sql.Schema { 444 return types.OkResultSchema 445 } 446 447 func (n *RevokeAll) IsReadOnly() bool { 448 return false 449 } 450 451 // String implements the interface sql.Node. 452 func (n *RevokeAll) String() string { 453 users := make([]string, len(n.Users)) 454 for i, user := range n.Users { 455 users[i] = user.String("") 456 } 457 return fmt.Sprintf("RevokeAll(From: %s)", strings.Join(users, ", ")) 458 } 459 460 // Resolved implements the interface sql.Node. 461 func (n *RevokeAll) Resolved() bool { 462 return true 463 } 464 465 // Children implements the interface sql.Node. 466 func (n *RevokeAll) Children() []sql.Node { 467 return nil 468 } 469 470 // WithChildren implements the interface sql.Node. 471 func (n *RevokeAll) WithChildren(children ...sql.Node) (sql.Node, error) { 472 if len(children) != 0 { 473 return nil, sql.ErrInvalidChildrenNumber.New(n, len(children), 0) 474 } 475 return n, nil 476 } 477 478 // CheckPrivileges implements the interface sql.Node. 479 func (n *RevokeAll) CheckPrivileges(ctx *sql.Context, opChecker sql.PrivilegedOperationChecker) bool { 480 createUser := sql.NewPrivilegedOperation(sql.PrivilegeCheckSubject{}, sql.PrivilegeType_CreateUser) 481 superUser := sql.NewPrivilegedOperation(sql.PrivilegeCheckSubject{}, sql.PrivilegeType_Super) 482 483 subject := sql.PrivilegeCheckSubject{Database: "mysql"} 484 mysqlUpdate := sql.NewPrivilegedOperation(subject, sql.PrivilegeType_Update) 485 486 return opChecker.UserHasPrivileges(ctx, createUser) || 487 opChecker.UserHasPrivileges(ctx, superUser) || 488 opChecker.UserHasPrivileges(ctx, mysqlUpdate) 489 } 490 491 // CollationCoercibility implements the interface sql.CollationCoercible. 492 func (*RevokeAll) CollationCoercibility(ctx *sql.Context) (collation sql.CollationID, coercibility byte) { 493 return sql.Collation_binary, 7 494 } 495 496 // RevokeRole represents the statement REVOKE [role...] FROM [user...]. 497 type RevokeRole struct { 498 Roles []UserName 499 TargetUsers []UserName 500 MySQLDb sql.Database 501 } 502 503 var _ sql.Node = (*RevokeRole)(nil) 504 var _ sql.Databaser = (*RevokeRole)(nil) 505 var _ sql.CollationCoercible = (*RevokeRole)(nil) 506 507 // NewRevokeRole returns a new RevokeRole node. 508 func NewRevokeRole(roles []UserName, users []UserName) *RevokeRole { 509 return &RevokeRole{ 510 Roles: roles, 511 TargetUsers: users, 512 MySQLDb: sql.UnresolvedDatabase("mysql"), 513 } 514 } 515 516 // Schema implements the interface sql.Node. 517 func (n *RevokeRole) Schema() sql.Schema { 518 return types.OkResultSchema 519 } 520 521 // String implements the interface sql.Node. 522 func (n *RevokeRole) String() string { 523 roles := make([]string, len(n.Roles)) 524 for i, role := range n.Roles { 525 roles[i] = role.String("") 526 } 527 users := make([]string, len(n.TargetUsers)) 528 for i, user := range n.TargetUsers { 529 users[i] = user.String("") 530 } 531 return fmt.Sprintf("RevokeRole(Roles: %s, From: %s)", strings.Join(roles, ", "), strings.Join(users, ", ")) 532 } 533 534 // Database implements the interface sql.Databaser. 535 func (n *RevokeRole) Database() sql.Database { 536 return n.MySQLDb 537 } 538 539 // WithDatabase implements the interface sql.Databaser. 540 func (n *RevokeRole) WithDatabase(db sql.Database) (sql.Node, error) { 541 nn := *n 542 nn.MySQLDb = db 543 return &nn, nil 544 } 545 546 // Resolved implements the interface sql.Node. 547 func (n *RevokeRole) Resolved() bool { 548 _, ok := n.MySQLDb.(sql.UnresolvedDatabase) 549 return !ok 550 } 551 552 func (n *RevokeRole) IsReadOnly() bool { 553 return false 554 } 555 556 // Children implements the interface sql.Node. 557 func (n *RevokeRole) Children() []sql.Node { 558 return nil 559 } 560 561 // WithChildren implements the interface sql.Node. 562 func (n *RevokeRole) WithChildren(children ...sql.Node) (sql.Node, error) { 563 if len(children) != 0 { 564 return nil, sql.ErrInvalidChildrenNumber.New(n, len(children), 0) 565 } 566 return n, nil 567 } 568 569 // CheckPrivileges implements the interface sql.Node. 570 func (n *RevokeRole) CheckPrivileges(ctx *sql.Context, opChecker sql.PrivilegedOperationChecker) bool { 571 if opChecker.UserHasPrivileges(ctx, 572 sql.NewPrivilegedOperation(sql.PrivilegeCheckSubject{}, sql.PrivilegeType_Super)) { 573 return true 574 } 575 //TODO: only active roles may be revoked if the SUPER privilege is not held 576 mysqlDb := n.MySQLDb.(*mysql_db.MySQLDb) 577 client := ctx.Session.Client() 578 579 reader := mysqlDb.Reader() 580 defer reader.Close() 581 582 user := mysqlDb.GetUser(reader, client.User, client.Address, false) 583 if user == nil { 584 return false 585 } 586 roleEdges := reader.GetToUserRoleEdges(mysql_db.RoleEdgesToKey{ 587 ToHost: user.Host, 588 ToUser: user.User, 589 }) 590 ROLES: 591 for _, roleName := range n.Roles { 592 role := mysqlDb.GetUser(reader, roleName.Name, roleName.Host, true) 593 if role == nil { 594 return false 595 } 596 for _, roleEdge := range roleEdges { 597 if roleEdge.FromUser == role.User && roleEdge.FromHost == role.Host && roleEdge.WithAdminOption { 598 continue ROLES 599 } 600 } 601 return false 602 } 603 return true 604 } 605 606 // CollationCoercibility implements the interface sql.CollationCoercible. 607 func (*RevokeRole) CollationCoercibility(ctx *sql.Context) (collation sql.CollationID, coercibility byte) { 608 return sql.Collation_binary, 7 609 } 610 611 // RevokeProxy represents the statement REVOKE PROXY. 612 type RevokeProxy struct { 613 On UserName 614 From []UserName 615 } 616 617 var _ sql.Node = (*RevokeProxy)(nil) 618 var _ sql.CollationCoercible = (*RevokeProxy)(nil) 619 620 // NewRevokeProxy returns a new RevokeProxy node. 621 func NewRevokeProxy(on UserName, from []UserName) *RevokeProxy { 622 return &RevokeProxy{ 623 On: on, 624 From: from, 625 } 626 } 627 628 // Schema implements the interface sql.Node. 629 func (n *RevokeProxy) Schema() sql.Schema { 630 return types.OkResultSchema 631 } 632 633 // String implements the interface sql.Node. 634 func (n *RevokeProxy) String() string { 635 users := make([]string, len(n.From)) 636 for i, user := range n.From { 637 users[i] = user.String("") 638 } 639 return fmt.Sprintf("RevokeProxy(On: %s, From: %s)", n.On.String(""), strings.Join(users, ", ")) 640 } 641 642 // Resolved implements the interface sql.Node. 643 func (n *RevokeProxy) Resolved() bool { 644 return true 645 } 646 647 func (n *RevokeProxy) IsReadOnly() bool { 648 return false 649 } 650 651 // Children implements the interface sql.Node. 652 func (n *RevokeProxy) Children() []sql.Node { 653 return nil 654 } 655 656 // WithChildren implements the interface sql.Node. 657 func (n *RevokeProxy) WithChildren(children ...sql.Node) (sql.Node, error) { 658 if len(children) != 0 { 659 return nil, sql.ErrInvalidChildrenNumber.New(n, len(children), 0) 660 } 661 return n, nil 662 } 663 664 // CheckPrivileges implements the interface sql.Node. 665 func (n *RevokeProxy) CheckPrivileges(ctx *sql.Context, opChecker sql.PrivilegedOperationChecker) bool { 666 //TODO: add this when proxy support is added 667 return true 668 } 669 670 // CollationCoercibility implements the interface sql.CollationCoercible. 671 func (*RevokeProxy) CollationCoercibility(ctx *sql.Context) (collation sql.CollationID, coercibility byte) { 672 return sql.Collation_binary, 7 673 } 674 675 // RowIter implements the interface sql.Node. 676 func (n *RevokeProxy) RowIter(ctx *sql.Context, row sql.Row) (sql.RowIter, error) { 677 return nil, fmt.Errorf("not yet implemented") 678 }