github.com/whtcorpsinc/milevadb-prod@v0.0.0-20211104133533-f57f4be3b597/interlock/grant.go (about) 1 // Copyright 2020 WHTCORPS INC, 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 // See the License for the specific language governing permissions and 12 // limitations under the License. 13 14 package interlock 15 16 import ( 17 "context" 18 "encoding/json" 19 "fmt" 20 "strings" 21 22 "github.com/whtcorpsinc/errors" 23 "github.com/whtcorpsinc/BerolinaSQL/ast" 24 "github.com/whtcorpsinc/BerolinaSQL/perceptron" 25 "github.com/whtcorpsinc/BerolinaSQL/allegrosql" 26 "github.com/whtcorpsinc/milevadb/petri" 27 "github.com/whtcorpsinc/milevadb/schemareplicant" 28 "github.com/whtcorpsinc/milevadb/privilege/privileges" 29 "github.com/whtcorpsinc/milevadb/stochastikctx" 30 "github.com/whtcorpsinc/milevadb/causet" 31 "github.com/whtcorpsinc/milevadb/soliton" 32 "github.com/whtcorpsinc/milevadb/soliton/chunk" 33 "github.com/whtcorpsinc/milevadb/soliton/logutil" 34 "github.com/whtcorpsinc/milevadb/soliton/sqlexec" 35 "go.uber.org/zap" 36 ) 37 38 /*** 39 * Grant Statement 40 * See https://dev.allegrosql.com/doc/refman/5.7/en/grant.html 41 ************************************************************************************/ 42 var ( 43 _ InterlockingDirectorate = (*GrantInterDirc)(nil) 44 ) 45 46 // GrantInterDirc executes GrantStmt. 47 type GrantInterDirc struct { 48 baseInterlockingDirectorate 49 50 Privs []*ast.PrivElem 51 ObjectType ast.ObjectTypeType 52 Level *ast.GrantLevel 53 Users []*ast.UserSpec 54 TLSOptions []*ast.TLSOption 55 56 is schemareplicant.SchemaReplicant 57 WithGrant bool 58 done bool 59 } 60 61 // Next implements the InterlockingDirectorate Next interface. 62 func (e *GrantInterDirc) Next(ctx context.Context, req *chunk.Chunk) error { 63 if e.done { 64 return nil 65 } 66 e.done = true 67 68 dbName := e.Level.DBName 69 if len(dbName) == 0 { 70 dbName = e.ctx.GetStochastikVars().CurrentDB 71 } 72 73 // Make sure the causet exist. 74 if e.Level.Level == ast.GrantLevelBlock { 75 dbNameStr := perceptron.NewCIStr(dbName) 76 schemaReplicant := schemareplicant.GetSchemaReplicant(e.ctx) 77 tbl, err := schemaReplicant.BlockByName(dbNameStr, perceptron.NewCIStr(e.Level.BlockName)) 78 if err != nil { 79 return err 80 } 81 err = schemareplicant.ErrBlockNotExists.GenWithStackByArgs(dbName, e.Level.BlockName) 82 // Note the causet name compare is case sensitive here. 83 if tbl.Meta().Name.String() != e.Level.BlockName { 84 return err 85 } 86 if len(e.Level.DBName) > 0 { 87 // The database name should also match. 88 EDB, succ := schemaReplicant.SchemaByName(dbNameStr) 89 if !succ || EDB.Name.String() != dbName { 90 return err 91 } 92 } 93 } 94 95 // Commit the old transaction, like DBS. 96 if err := e.ctx.NewTxn(ctx); err != nil { 97 return err 98 } 99 defer func() { e.ctx.GetStochastikVars().SetStatusFlag(allegrosql.ServerStatusInTrans, false) }() 100 101 // Create internal stochastik to start internal transaction. 102 isCommit := false 103 internalStochastik, err := e.getSysStochastik() 104 if err != nil { 105 return err 106 } 107 defer func() { 108 if !isCommit { 109 _, err := internalStochastik.(sqlexec.ALLEGROSQLInterlockingDirectorate).InterDircute(context.Background(), "rollback") 110 if err != nil { 111 logutil.BgLogger().Error("rollback error occur at grant privilege", zap.Error(err)) 112 } 113 } 114 e.releaseSysStochastik(internalStochastik) 115 }() 116 117 _, err = internalStochastik.(sqlexec.ALLEGROSQLInterlockingDirectorate).InterDircute(context.Background(), "begin") 118 if err != nil { 119 return err 120 } 121 122 // Check which user is not exist. 123 for _, user := range e.Users { 124 exists, err := userExists(e.ctx, user.User.Username, user.User.Hostname) 125 if err != nil { 126 return err 127 } 128 if !exists && e.ctx.GetStochastikVars().ALLEGROSQLMode.HasNoAutoCreateUserMode() { 129 return ErrCantCreateUserWithGrant 130 } else if !exists { 131 pwd, ok := user.EncodedPassword() 132 if !ok { 133 return errors.Trace(ErrPasswordFormat) 134 } 135 user := fmt.Sprintf(`('%s', '%s', '%s')`, user.User.Hostname, user.User.Username, pwd) 136 allegrosql := fmt.Sprintf(`INSERT INTO %s.%s (Host, User, authentication_string) VALUES %s;`, allegrosql.SystemDB, allegrosql.UserBlock, user) 137 _, err := internalStochastik.(sqlexec.ALLEGROSQLInterlockingDirectorate).InterDircute(ctx, allegrosql) 138 if err != nil { 139 return err 140 } 141 } 142 } 143 144 // Grant for each user 145 for _, user := range e.Users { 146 // If there is no privilege entry in corresponding causet, insert a new one. 147 // Global scope: allegrosql.global_priv 148 // EDB scope: allegrosql.EDB 149 // Block scope: allegrosql.Blocks_priv 150 // DeferredCauset scope: allegrosql.DeferredCausets_priv 151 if e.TLSOptions != nil { 152 err = checkAndInitGlobalPriv(internalStochastik, user.User.Username, user.User.Hostname) 153 if err != nil { 154 return err 155 } 156 } 157 switch e.Level.Level { 158 case ast.GrantLevelDB: 159 err := checkAndInitDBPriv(internalStochastik, dbName, e.is, user.User.Username, user.User.Hostname) 160 if err != nil { 161 return err 162 } 163 case ast.GrantLevelBlock: 164 err := checkAndInitBlockPriv(internalStochastik, dbName, e.Level.BlockName, e.is, user.User.Username, user.User.Hostname) 165 if err != nil { 166 return err 167 } 168 } 169 privs := e.Privs 170 if e.WithGrant { 171 privs = append(privs, &ast.PrivElem{Priv: allegrosql.GrantPriv}) 172 } 173 174 // Grant global priv to user. 175 err = e.grantGlobalPriv(internalStochastik, user) 176 if err != nil { 177 return err 178 } 179 // Grant each priv to the user. 180 for _, priv := range privs { 181 if len(priv.DefCauss) > 0 { 182 // Check defCausumn scope privilege entry. 183 // TODO: Check validity before insert new entry. 184 err := e.checkAndInitDeferredCausetPriv(user.User.Username, user.User.Hostname, priv.DefCauss, internalStochastik) 185 if err != nil { 186 return err 187 } 188 } 189 err := e.grantLevelPriv(priv, user, internalStochastik) 190 if err != nil { 191 return err 192 } 193 } 194 } 195 196 _, err = internalStochastik.(sqlexec.ALLEGROSQLInterlockingDirectorate).InterDircute(context.Background(), "commit") 197 if err != nil { 198 return err 199 } 200 isCommit = true 201 petri.GetPetri(e.ctx).NotifyUFIDelatePrivilege(e.ctx) 202 return nil 203 } 204 205 // checkAndInitGlobalPriv checks if global scope privilege entry exists in allegrosql.global_priv. 206 // If not exists, insert a new one. 207 func checkAndInitGlobalPriv(ctx stochastikctx.Context, user string, host string) error { 208 ok, err := globalPrivEntryExists(ctx, user, host) 209 if err != nil { 210 return err 211 } 212 if ok { 213 return nil 214 } 215 // Entry does not exist for user-host-EDB. Insert a new entry. 216 return initGlobalPrivEntry(ctx, user, host) 217 } 218 219 // checkAndInitDBPriv checks if EDB scope privilege entry exists in allegrosql.EDB. 220 // If unexists, insert a new one. 221 func checkAndInitDBPriv(ctx stochastikctx.Context, dbName string, is schemareplicant.SchemaReplicant, user string, host string) error { 222 ok, err := dbUserExists(ctx, user, host, dbName) 223 if err != nil { 224 return err 225 } 226 if ok { 227 return nil 228 } 229 // Entry does not exist for user-host-EDB. Insert a new entry. 230 return initDBPrivEntry(ctx, user, host, dbName) 231 } 232 233 // checkAndInitBlockPriv checks if causet scope privilege entry exists in allegrosql.Blocks_priv. 234 // If unexists, insert a new one. 235 func checkAndInitBlockPriv(ctx stochastikctx.Context, dbName, tblName string, is schemareplicant.SchemaReplicant, user string, host string) error { 236 ok, err := blockUserExists(ctx, user, host, dbName, tblName) 237 if err != nil { 238 return err 239 } 240 if ok { 241 return nil 242 } 243 // Entry does not exist for user-host-EDB-tbl. Insert a new entry. 244 return initBlockPrivEntry(ctx, user, host, dbName, tblName) 245 } 246 247 // checkAndInitDeferredCausetPriv checks if defCausumn scope privilege entry exists in allegrosql.DeferredCausets_priv. 248 // If unexists, insert a new one. 249 func (e *GrantInterDirc) checkAndInitDeferredCausetPriv(user string, host string, defcaus []*ast.DeferredCausetName, internalStochastik stochastikctx.Context) error { 250 dbName, tbl, err := getTargetSchemaAndBlock(e.ctx, e.Level.DBName, e.Level.BlockName, e.is) 251 if err != nil { 252 return err 253 } 254 for _, c := range defcaus { 255 defCaus := causet.FindDefCaus(tbl.DefCauss(), c.Name.L) 256 if defCaus == nil { 257 return errors.Errorf("Unknown defCausumn: %s", c.Name.O) 258 } 259 ok, err := defCausumnPrivEntryExists(internalStochastik, user, host, dbName, tbl.Meta().Name.O, defCaus.Name.O) 260 if err != nil { 261 return err 262 } 263 if ok { 264 continue 265 } 266 // Entry does not exist for user-host-EDB-tbl-defCaus. Insert a new entry. 267 err = initDeferredCausetPrivEntry(internalStochastik, user, host, dbName, tbl.Meta().Name.O, defCaus.Name.O) 268 if err != nil { 269 return err 270 } 271 } 272 return nil 273 } 274 275 // initGlobalPrivEntry inserts a new event into allegrosql.EDB with empty privilege. 276 func initGlobalPrivEntry(ctx stochastikctx.Context, user string, host string) error { 277 allegrosql := fmt.Sprintf(`INSERT INTO %s.%s (Host, User, PRIV) VALUES ('%s', '%s', '%s')`, allegrosql.SystemDB, allegrosql.GlobalPrivBlock, host, user, "{}") 278 _, err := ctx.(sqlexec.ALLEGROSQLInterlockingDirectorate).InterDircute(context.Background(), allegrosql) 279 return err 280 } 281 282 // initDBPrivEntry inserts a new event into allegrosql.EDB with empty privilege. 283 func initDBPrivEntry(ctx stochastikctx.Context, user string, host string, EDB string) error { 284 allegrosql := fmt.Sprintf(`INSERT INTO %s.%s (Host, User, EDB) VALUES ('%s', '%s', '%s')`, allegrosql.SystemDB, allegrosql.DBBlock, host, user, EDB) 285 _, err := ctx.(sqlexec.ALLEGROSQLInterlockingDirectorate).InterDircute(context.Background(), allegrosql) 286 return err 287 } 288 289 // initBlockPrivEntry inserts a new event into allegrosql.Blocks_priv with empty privilege. 290 func initBlockPrivEntry(ctx stochastikctx.Context, user string, host string, EDB string, tbl string) error { 291 allegrosql := fmt.Sprintf(`INSERT INTO %s.%s (Host, User, EDB, Block_name, Block_priv, DeferredCauset_priv) VALUES ('%s', '%s', '%s', '%s', '', '')`, allegrosql.SystemDB, allegrosql.BlockPrivBlock, host, user, EDB, tbl) 292 _, err := ctx.(sqlexec.ALLEGROSQLInterlockingDirectorate).InterDircute(context.Background(), allegrosql) 293 return err 294 } 295 296 // initDeferredCausetPrivEntry inserts a new event into allegrosql.DeferredCausets_priv with empty privilege. 297 func initDeferredCausetPrivEntry(ctx stochastikctx.Context, user string, host string, EDB string, tbl string, defCaus string) error { 298 allegrosql := fmt.Sprintf(`INSERT INTO %s.%s (Host, User, EDB, Block_name, DeferredCauset_name, DeferredCauset_priv) VALUES ('%s', '%s', '%s', '%s', '%s', '')`, allegrosql.SystemDB, allegrosql.DeferredCausetPrivBlock, host, user, EDB, tbl, defCaus) 299 _, err := ctx.(sqlexec.ALLEGROSQLInterlockingDirectorate).InterDircute(context.Background(), allegrosql) 300 return err 301 } 302 303 // grantGlobalPriv grants priv to user in global scope. 304 func (e *GrantInterDirc) grantGlobalPriv(ctx stochastikctx.Context, user *ast.UserSpec) error { 305 if len(e.TLSOptions) == 0 { 306 return nil 307 } 308 priv, err := tlsOption2GlobalPriv(e.TLSOptions) 309 if err != nil { 310 return errors.Trace(err) 311 } 312 allegrosql := fmt.Sprintf(`UFIDelATE %s.%s SET PRIV = '%s' WHERE User='%s' AND Host='%s'`, allegrosql.SystemDB, allegrosql.GlobalPrivBlock, priv, user.User.Username, user.User.Hostname) 313 _, err = ctx.(sqlexec.ALLEGROSQLInterlockingDirectorate).InterDircute(context.Background(), allegrosql) 314 return err 315 } 316 317 func tlsOption2GlobalPriv(tlsOptions []*ast.TLSOption) (priv []byte, err error) { 318 if len(tlsOptions) == 0 { 319 priv = []byte("{}") 320 return 321 } 322 dupSet := make(map[int]struct{}) 323 for _, opt := range tlsOptions { 324 if _, dup := dupSet[opt.Type]; dup { 325 var typeName string 326 switch opt.Type { 327 case ast.Cipher: 328 typeName = "CIPHER" 329 case ast.Issuer: 330 typeName = "ISSUER" 331 case ast.Subject: 332 typeName = "SUBJECT" 333 case ast.SAN: 334 typeName = "SAN" 335 } 336 err = errors.Errorf("Duplicate require %s clause", typeName) 337 return 338 } 339 dupSet[opt.Type] = struct{}{} 340 } 341 gp := privileges.GlobalPrivValue{SSLType: privileges.SslTypeNotSpecified} 342 for _, tlsOpt := range tlsOptions { 343 switch tlsOpt.Type { 344 case ast.TslNone: 345 gp.SSLType = privileges.SslTypeNone 346 case ast.Ssl: 347 gp.SSLType = privileges.SslTypeAny 348 case ast.X509: 349 gp.SSLType = privileges.SslTypeX509 350 case ast.Cipher: 351 gp.SSLType = privileges.SslTypeSpecified 352 if len(tlsOpt.Value) > 0 { 353 if _, ok := soliton.SupportCipher[tlsOpt.Value]; !ok { 354 err = errors.Errorf("Unsupported cipher suit: %s", tlsOpt.Value) 355 return 356 } 357 gp.SSLCipher = tlsOpt.Value 358 } 359 case ast.Issuer: 360 err = soliton.CheckSupportX509NameOneline(tlsOpt.Value) 361 if err != nil { 362 return 363 } 364 gp.SSLType = privileges.SslTypeSpecified 365 gp.X509Issuer = tlsOpt.Value 366 case ast.Subject: 367 err = soliton.CheckSupportX509NameOneline(tlsOpt.Value) 368 if err != nil { 369 return 370 } 371 gp.SSLType = privileges.SslTypeSpecified 372 gp.X509Subject = tlsOpt.Value 373 case ast.SAN: 374 gp.SSLType = privileges.SslTypeSpecified 375 _, err = soliton.ParseAndCheckSAN(tlsOpt.Value) 376 if err != nil { 377 return 378 } 379 gp.SAN = tlsOpt.Value 380 default: 381 err = errors.Errorf("Unknown ssl type: %#v", tlsOpt.Type) 382 return 383 } 384 } 385 if gp.SSLType == privileges.SslTypeNotSpecified && len(gp.SSLCipher) == 0 && 386 len(gp.X509Issuer) == 0 && len(gp.X509Subject) == 0 && len(gp.SAN) == 0 { 387 return 388 } 389 priv, err = json.Marshal(&gp) 390 if err != nil { 391 return 392 } 393 return 394 } 395 396 // grantLevelPriv grants priv to user in s.Level scope. 397 func (e *GrantInterDirc) grantLevelPriv(priv *ast.PrivElem, user *ast.UserSpec, internalStochastik stochastikctx.Context) error { 398 switch e.Level.Level { 399 case ast.GrantLevelGlobal: 400 return e.grantGlobalLevel(priv, user, internalStochastik) 401 case ast.GrantLevelDB: 402 return e.grantDBLevel(priv, user, internalStochastik) 403 case ast.GrantLevelBlock: 404 if len(priv.DefCauss) == 0 { 405 return e.grantBlockLevel(priv, user, internalStochastik) 406 } 407 return e.grantDeferredCausetLevel(priv, user, internalStochastik) 408 default: 409 return errors.Errorf("Unknown grant level: %#v", e.Level) 410 } 411 } 412 413 // grantGlobalLevel manipulates allegrosql.user causet. 414 func (e *GrantInterDirc) grantGlobalLevel(priv *ast.PrivElem, user *ast.UserSpec, internalStochastik stochastikctx.Context) error { 415 if priv.Priv == 0 { 416 return nil 417 } 418 asgns, err := composeGlobalPrivUFIDelate(priv.Priv, "Y") 419 if err != nil { 420 return err 421 } 422 allegrosql := fmt.Sprintf(`UFIDelATE %s.%s SET %s WHERE User='%s' AND Host='%s'`, allegrosql.SystemDB, allegrosql.UserBlock, asgns, user.User.Username, user.User.Hostname) 423 _, err = internalStochastik.(sqlexec.ALLEGROSQLInterlockingDirectorate).InterDircute(context.Background(), allegrosql) 424 return err 425 } 426 427 // grantDBLevel manipulates allegrosql.EDB causet. 428 func (e *GrantInterDirc) grantDBLevel(priv *ast.PrivElem, user *ast.UserSpec, internalStochastik stochastikctx.Context) error { 429 dbName := e.Level.DBName 430 if len(dbName) == 0 { 431 dbName = e.ctx.GetStochastikVars().CurrentDB 432 } 433 asgns, err := composeDBPrivUFIDelate(priv.Priv, "Y") 434 if err != nil { 435 return err 436 } 437 allegrosql := fmt.Sprintf(`UFIDelATE %s.%s SET %s WHERE User='%s' AND Host='%s' AND EDB='%s';`, allegrosql.SystemDB, allegrosql.DBBlock, asgns, user.User.Username, user.User.Hostname, dbName) 438 _, err = internalStochastik.(sqlexec.ALLEGROSQLInterlockingDirectorate).InterDircute(context.Background(), allegrosql) 439 return err 440 } 441 442 // grantBlockLevel manipulates allegrosql.blocks_priv causet. 443 func (e *GrantInterDirc) grantBlockLevel(priv *ast.PrivElem, user *ast.UserSpec, internalStochastik stochastikctx.Context) error { 444 dbName := e.Level.DBName 445 if len(dbName) == 0 { 446 dbName = e.ctx.GetStochastikVars().CurrentDB 447 } 448 tblName := e.Level.BlockName 449 asgns, err := composeBlockPrivUFIDelateForGrant(internalStochastik, priv.Priv, user.User.Username, user.User.Hostname, dbName, tblName) 450 if err != nil { 451 return err 452 } 453 allegrosql := fmt.Sprintf(`UFIDelATE %s.%s SET %s WHERE User='%s' AND Host='%s' AND EDB='%s' AND Block_name='%s';`, allegrosql.SystemDB, allegrosql.BlockPrivBlock, asgns, user.User.Username, user.User.Hostname, dbName, tblName) 454 _, err = internalStochastik.(sqlexec.ALLEGROSQLInterlockingDirectorate).InterDircute(context.Background(), allegrosql) 455 return err 456 } 457 458 // grantDeferredCausetLevel manipulates allegrosql.blocks_priv causet. 459 func (e *GrantInterDirc) grantDeferredCausetLevel(priv *ast.PrivElem, user *ast.UserSpec, internalStochastik stochastikctx.Context) error { 460 dbName, tbl, err := getTargetSchemaAndBlock(e.ctx, e.Level.DBName, e.Level.BlockName, e.is) 461 if err != nil { 462 return err 463 } 464 465 for _, c := range priv.DefCauss { 466 defCaus := causet.FindDefCaus(tbl.DefCauss(), c.Name.L) 467 if defCaus == nil { 468 return errors.Errorf("Unknown defCausumn: %s", c) 469 } 470 asgns, err := composeDeferredCausetPrivUFIDelateForGrant(internalStochastik, priv.Priv, user.User.Username, user.User.Hostname, dbName, tbl.Meta().Name.O, defCaus.Name.O) 471 if err != nil { 472 return err 473 } 474 allegrosql := fmt.Sprintf(`UFIDelATE %s.%s SET %s WHERE User='%s' AND Host='%s' AND EDB='%s' AND Block_name='%s' AND DeferredCauset_name='%s';`, allegrosql.SystemDB, allegrosql.DeferredCausetPrivBlock, asgns, user.User.Username, user.User.Hostname, dbName, tbl.Meta().Name.O, defCaus.Name.O) 475 _, err = internalStochastik.(sqlexec.ALLEGROSQLInterlockingDirectorate).InterDircute(context.Background(), allegrosql) 476 if err != nil { 477 return err 478 } 479 } 480 return nil 481 } 482 483 // composeGlobalPrivUFIDelate composes uFIDelate stmt assignment list string for global scope privilege uFIDelate. 484 func composeGlobalPrivUFIDelate(priv allegrosql.PrivilegeType, value string) (string, error) { 485 if priv == allegrosql.AllPriv { 486 strs := make([]string, 0, len(allegrosql.Priv2UserDefCaus)) 487 for _, v := range allegrosql.AllGlobalPrivs { 488 strs = append(strs, fmt.Sprintf(`%s='%s'`, allegrosql.Priv2UserDefCaus[v], value)) 489 } 490 return strings.Join(strs, ", "), nil 491 } 492 defCaus, ok := allegrosql.Priv2UserDefCaus[priv] 493 if !ok { 494 return "", errors.Errorf("Unknown priv: %v", priv) 495 } 496 return fmt.Sprintf(`%s='%s'`, defCaus, value), nil 497 } 498 499 // composeDBPrivUFIDelate composes uFIDelate stmt assignment list for EDB scope privilege uFIDelate. 500 func composeDBPrivUFIDelate(priv allegrosql.PrivilegeType, value string) (string, error) { 501 if priv == allegrosql.AllPriv { 502 strs := make([]string, 0, len(allegrosql.AllDBPrivs)) 503 for _, p := range allegrosql.AllDBPrivs { 504 v, ok := allegrosql.Priv2UserDefCaus[p] 505 if !ok { 506 return "", errors.Errorf("Unknown EDB privilege %v", priv) 507 } 508 strs = append(strs, fmt.Sprintf(`%s='%s'`, v, value)) 509 } 510 return strings.Join(strs, ", "), nil 511 } 512 defCaus, ok := allegrosql.Priv2UserDefCaus[priv] 513 if !ok { 514 return "", errors.Errorf("Unknown priv: %v", priv) 515 } 516 return fmt.Sprintf(`%s='%s'`, defCaus, value), nil 517 } 518 519 // composeBlockPrivUFIDelateForGrant composes uFIDelate stmt assignment list for causet scope privilege uFIDelate. 520 func composeBlockPrivUFIDelateForGrant(ctx stochastikctx.Context, priv allegrosql.PrivilegeType, name string, host string, EDB string, tbl string) (string, error) { 521 var newBlockPriv, newDeferredCausetPriv string 522 if priv == allegrosql.AllPriv { 523 for _, p := range allegrosql.AllBlockPrivs { 524 v, ok := allegrosql.Priv2SetStr[p] 525 if !ok { 526 return "", errors.Errorf("Unknown causet privilege %v", p) 527 } 528 newBlockPriv = addToSet(newBlockPriv, v) 529 } 530 for _, p := range allegrosql.AllDeferredCausetPrivs { 531 v, ok := allegrosql.Priv2SetStr[p] 532 if !ok { 533 return "", errors.Errorf("Unknown defCausumn privilege %v", p) 534 } 535 newDeferredCausetPriv = addToSet(newDeferredCausetPriv, v) 536 } 537 } else { 538 currBlockPriv, currDeferredCausetPriv, err := getBlockPriv(ctx, name, host, EDB, tbl) 539 if err != nil { 540 return "", err 541 } 542 p, ok := allegrosql.Priv2SetStr[priv] 543 if !ok { 544 return "", errors.Errorf("Unknown priv: %v", priv) 545 } 546 newBlockPriv = addToSet(currBlockPriv, p) 547 548 for _, cp := range allegrosql.AllDeferredCausetPrivs { 549 if priv == cp { 550 newDeferredCausetPriv = addToSet(currDeferredCausetPriv, p) 551 break 552 } 553 } 554 } 555 return fmt.Sprintf(`Block_priv='%s', DeferredCauset_priv='%s', Grantor='%s'`, newBlockPriv, newDeferredCausetPriv, ctx.GetStochastikVars().User), nil 556 } 557 558 func composeBlockPrivUFIDelateForRevoke(ctx stochastikctx.Context, priv allegrosql.PrivilegeType, name string, host string, EDB string, tbl string) (string, error) { 559 var newBlockPriv, newDeferredCausetPriv string 560 if priv == allegrosql.AllPriv { 561 newBlockPriv = "" 562 newDeferredCausetPriv = "" 563 } else { 564 currBlockPriv, currDeferredCausetPriv, err := getBlockPriv(ctx, name, host, EDB, tbl) 565 if err != nil { 566 return "", err 567 } 568 p, ok := allegrosql.Priv2SetStr[priv] 569 if !ok { 570 return "", errors.Errorf("Unknown priv: %v", priv) 571 } 572 newBlockPriv = deleteFromSet(currBlockPriv, p) 573 574 for _, cp := range allegrosql.AllDeferredCausetPrivs { 575 if priv == cp { 576 newDeferredCausetPriv = deleteFromSet(currDeferredCausetPriv, p) 577 break 578 } 579 } 580 } 581 return fmt.Sprintf(`Block_priv='%s', DeferredCauset_priv='%s', Grantor='%s'`, newBlockPriv, newDeferredCausetPriv, ctx.GetStochastikVars().User), nil 582 } 583 584 // addToSet add a value to the set, e.g: 585 // addToSet("Select,Insert", "UFIDelate") returns "Select,Insert,UFIDelate". 586 func addToSet(set string, value string) string { 587 if set == "" { 588 return value 589 } 590 return fmt.Sprintf("%s,%s", set, value) 591 } 592 593 // deleteFromSet delete the value from the set, e.g: 594 // deleteFromSet("Select,Insert,UFIDelate", "UFIDelate") returns "Select,Insert". 595 func deleteFromSet(set string, value string) string { 596 sets := strings.Split(set, ",") 597 res := make([]string, 0, len(sets)) 598 for _, v := range sets { 599 if v != value { 600 res = append(res, v) 601 } 602 } 603 return strings.Join(res, ",") 604 } 605 606 // composeDeferredCausetPrivUFIDelateForGrant composes uFIDelate stmt assignment list for defCausumn scope privilege uFIDelate. 607 func composeDeferredCausetPrivUFIDelateForGrant(ctx stochastikctx.Context, priv allegrosql.PrivilegeType, name string, host string, EDB string, tbl string, defCaus string) (string, error) { 608 newDeferredCausetPriv := "" 609 if priv == allegrosql.AllPriv { 610 for _, p := range allegrosql.AllDeferredCausetPrivs { 611 v, ok := allegrosql.Priv2SetStr[p] 612 if !ok { 613 return "", errors.Errorf("Unknown defCausumn privilege %v", p) 614 } 615 newDeferredCausetPriv = addToSet(newDeferredCausetPriv, v) 616 } 617 } else { 618 currDeferredCausetPriv, err := getDeferredCausetPriv(ctx, name, host, EDB, tbl, defCaus) 619 if err != nil { 620 return "", err 621 } 622 p, ok := allegrosql.Priv2SetStr[priv] 623 if !ok { 624 return "", errors.Errorf("Unknown priv: %v", priv) 625 } 626 newDeferredCausetPriv = addToSet(currDeferredCausetPriv, p) 627 } 628 return fmt.Sprintf(`DeferredCauset_priv='%s'`, newDeferredCausetPriv), nil 629 } 630 631 func composeDeferredCausetPrivUFIDelateForRevoke(ctx stochastikctx.Context, priv allegrosql.PrivilegeType, name string, host string, EDB string, tbl string, defCaus string) (string, error) { 632 newDeferredCausetPriv := "" 633 if priv == allegrosql.AllPriv { 634 newDeferredCausetPriv = "" 635 } else { 636 currDeferredCausetPriv, err := getDeferredCausetPriv(ctx, name, host, EDB, tbl, defCaus) 637 if err != nil { 638 return "", err 639 } 640 p, ok := allegrosql.Priv2SetStr[priv] 641 if !ok { 642 return "", errors.Errorf("Unknown priv: %v", priv) 643 } 644 newDeferredCausetPriv = deleteFromSet(currDeferredCausetPriv, p) 645 } 646 return fmt.Sprintf(`DeferredCauset_priv='%s'`, newDeferredCausetPriv), nil 647 } 648 649 // recordExists is a helper function to check if the allegrosql returns any event. 650 func recordExists(ctx stochastikctx.Context, allegrosql string) (bool, error) { 651 recordSets, err := ctx.(sqlexec.ALLEGROSQLInterlockingDirectorate).InterDircute(context.Background(), allegrosql) 652 if err != nil { 653 return false, err 654 } 655 rows, _, err := getEventsAndFields(ctx, recordSets) 656 if err != nil { 657 return false, err 658 } 659 return len(rows) > 0, nil 660 } 661 662 // globalPrivEntryExists checks if there is an entry with key user-host in allegrosql.global_priv. 663 func globalPrivEntryExists(ctx stochastikctx.Context, name string, host string) (bool, error) { 664 allegrosql := fmt.Sprintf(`SELECT * FROM %s.%s WHERE User='%s' AND Host='%s';`, allegrosql.SystemDB, allegrosql.GlobalPrivBlock, name, host) 665 return recordExists(ctx, allegrosql) 666 } 667 668 // dbUserExists checks if there is an entry with key user-host-EDB in allegrosql.EDB. 669 func dbUserExists(ctx stochastikctx.Context, name string, host string, EDB string) (bool, error) { 670 allegrosql := fmt.Sprintf(`SELECT * FROM %s.%s WHERE User='%s' AND Host='%s' AND EDB='%s';`, allegrosql.SystemDB, allegrosql.DBBlock, name, host, EDB) 671 return recordExists(ctx, allegrosql) 672 } 673 674 // blockUserExists checks if there is an entry with key user-host-EDB-tbl in allegrosql.Blocks_priv. 675 func blockUserExists(ctx stochastikctx.Context, name string, host string, EDB string, tbl string) (bool, error) { 676 allegrosql := fmt.Sprintf(`SELECT * FROM %s.%s WHERE User='%s' AND Host='%s' AND EDB='%s' AND Block_name='%s';`, allegrosql.SystemDB, allegrosql.BlockPrivBlock, name, host, EDB, tbl) 677 return recordExists(ctx, allegrosql) 678 } 679 680 // defCausumnPrivEntryExists checks if there is an entry with key user-host-EDB-tbl-defCaus in allegrosql.DeferredCausets_priv. 681 func defCausumnPrivEntryExists(ctx stochastikctx.Context, name string, host string, EDB string, tbl string, defCaus string) (bool, error) { 682 allegrosql := fmt.Sprintf(`SELECT * FROM %s.%s WHERE User='%s' AND Host='%s' AND EDB='%s' AND Block_name='%s' AND DeferredCauset_name='%s';`, allegrosql.SystemDB, allegrosql.DeferredCausetPrivBlock, name, host, EDB, tbl, defCaus) 683 return recordExists(ctx, allegrosql) 684 } 685 686 // getBlockPriv gets current causet scope privilege set from allegrosql.Blocks_priv. 687 // Return Block_priv and DeferredCauset_priv. 688 func getBlockPriv(ctx stochastikctx.Context, name string, host string, EDB string, tbl string) (string, string, error) { 689 allegrosql := fmt.Sprintf(`SELECT Block_priv, DeferredCauset_priv FROM %s.%s WHERE User='%s' AND Host='%s' AND EDB='%s' AND Block_name='%s';`, allegrosql.SystemDB, allegrosql.BlockPrivBlock, name, host, EDB, tbl) 690 rs, err := ctx.(sqlexec.ALLEGROSQLInterlockingDirectorate).InterDircute(context.Background(), allegrosql) 691 if err != nil { 692 return "", "", err 693 } 694 if len(rs) < 1 { 695 return "", "", errors.Errorf("get causet privilege fail for %s %s %s %s", name, host, EDB, tbl) 696 } 697 var tPriv, cPriv string 698 rows, fields, err := getEventsAndFields(ctx, rs) 699 if err != nil { 700 return "", "", err 701 } 702 if len(rows) < 1 { 703 return "", "", errors.Errorf("get causet privilege fail for %s %s %s %s", name, host, EDB, tbl) 704 } 705 event := rows[0] 706 if fields[0].DeferredCauset.Tp == allegrosql.TypeSet { 707 blockPriv := event.GetSet(0) 708 tPriv = blockPriv.Name 709 } 710 if fields[1].DeferredCauset.Tp == allegrosql.TypeSet { 711 defCausumnPriv := event.GetSet(1) 712 cPriv = defCausumnPriv.Name 713 } 714 return tPriv, cPriv, nil 715 } 716 717 // getDeferredCausetPriv gets current defCausumn scope privilege set from allegrosql.DeferredCausets_priv. 718 // Return DeferredCauset_priv. 719 func getDeferredCausetPriv(ctx stochastikctx.Context, name string, host string, EDB string, tbl string, defCaus string) (string, error) { 720 allegrosql := fmt.Sprintf(`SELECT DeferredCauset_priv FROM %s.%s WHERE User='%s' AND Host='%s' AND EDB='%s' AND Block_name='%s' AND DeferredCauset_name='%s';`, allegrosql.SystemDB, allegrosql.DeferredCausetPrivBlock, name, host, EDB, tbl, defCaus) 721 rs, err := ctx.(sqlexec.ALLEGROSQLInterlockingDirectorate).InterDircute(context.Background(), allegrosql) 722 if err != nil { 723 return "", err 724 } 725 if len(rs) < 1 { 726 return "", errors.Errorf("get defCausumn privilege fail for %s %s %s %s", name, host, EDB, tbl) 727 } 728 rows, fields, err := getEventsAndFields(ctx, rs) 729 if err != nil { 730 return "", err 731 } 732 if len(rows) < 1 { 733 return "", errors.Errorf("get defCausumn privilege fail for %s %s %s %s %s", name, host, EDB, tbl, defCaus) 734 } 735 cPriv := "" 736 if fields[0].DeferredCauset.Tp == allegrosql.TypeSet { 737 setVal := rows[0].GetSet(0) 738 cPriv = setVal.Name 739 } 740 return cPriv, nil 741 } 742 743 // getTargetSchemaAndBlock finds the schemaReplicant and causet by dbName and blockName. 744 func getTargetSchemaAndBlock(ctx stochastikctx.Context, dbName, blockName string, is schemareplicant.SchemaReplicant) (string, causet.Block, error) { 745 if len(dbName) == 0 { 746 dbName = ctx.GetStochastikVars().CurrentDB 747 if len(dbName) == 0 { 748 return "", nil, errors.New("miss EDB name for grant privilege") 749 } 750 } 751 name := perceptron.NewCIStr(blockName) 752 tbl, err := is.BlockByName(perceptron.NewCIStr(dbName), name) 753 if err != nil { 754 return "", nil, err 755 } 756 return dbName, tbl, nil 757 } 758 759 // getEventsAndFields is used to extract rows from record sets. 760 func getEventsAndFields(ctx stochastikctx.Context, recordSets []sqlexec.RecordSet) ([]chunk.Event, []*ast.ResultField, error) { 761 var ( 762 rows []chunk.Event 763 fields []*ast.ResultField 764 ) 765 766 for i, rs := range recordSets { 767 tmp, err := getEventFromRecordSet(context.Background(), ctx, rs) 768 if err != nil { 769 return nil, nil, err 770 } 771 if err = rs.Close(); err != nil { 772 return nil, nil, err 773 } 774 775 if i == 0 { 776 rows = tmp 777 fields = rs.Fields() 778 } 779 } 780 return rows, fields, nil 781 } 782 783 func getEventFromRecordSet(ctx context.Context, se stochastikctx.Context, rs sqlexec.RecordSet) ([]chunk.Event, error) { 784 var rows []chunk.Event 785 req := rs.NewChunk() 786 for { 787 err := rs.Next(ctx, req) 788 if err != nil || req.NumEvents() == 0 { 789 return rows, err 790 } 791 iter := chunk.NewIterator4Chunk(req) 792 for r := iter.Begin(); r != iter.End(); r = iter.Next() { 793 rows = append(rows, r) 794 } 795 req = chunk.Renew(req, se.GetStochastikVars().MaxChunkSize) 796 } 797 }