github.com/whtcorpsinc/milevadb-prod@v0.0.0-20211104133533-f57f4be3b597/interlock/revoke.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 "fmt" 19 20 "github.com/whtcorpsinc/errors" 21 "github.com/whtcorpsinc/BerolinaSQL/ast" 22 "github.com/whtcorpsinc/BerolinaSQL/allegrosql" 23 "github.com/whtcorpsinc/milevadb/petri" 24 "github.com/whtcorpsinc/milevadb/schemareplicant" 25 "github.com/whtcorpsinc/milevadb/stochastikctx" 26 "github.com/whtcorpsinc/milevadb/causet" 27 "github.com/whtcorpsinc/milevadb/soliton/chunk" 28 "github.com/whtcorpsinc/milevadb/soliton/logutil" 29 "github.com/whtcorpsinc/milevadb/soliton/sqlexec" 30 "go.uber.org/zap" 31 ) 32 33 /*** 34 * Revoke Statement 35 * See https://dev.allegrosql.com/doc/refman/5.7/en/revoke.html 36 ************************************************************************************/ 37 var ( 38 _ InterlockingDirectorate = (*RevokeInterDirc)(nil) 39 ) 40 41 // RevokeInterDirc executes RevokeStmt. 42 type RevokeInterDirc struct { 43 baseInterlockingDirectorate 44 45 Privs []*ast.PrivElem 46 ObjectType ast.ObjectTypeType 47 Level *ast.GrantLevel 48 Users []*ast.UserSpec 49 50 ctx stochastikctx.Context 51 is schemareplicant.SchemaReplicant 52 done bool 53 } 54 55 // Next implements the InterlockingDirectorate Next interface. 56 func (e *RevokeInterDirc) Next(ctx context.Context, req *chunk.Chunk) error { 57 if e.done { 58 return nil 59 } 60 e.done = true 61 62 // Commit the old transaction, like DBS. 63 if err := e.ctx.NewTxn(ctx); err != nil { 64 return err 65 } 66 defer func() { e.ctx.GetStochastikVars().SetStatusFlag(allegrosql.ServerStatusInTrans, false) }() 67 68 // Create internal stochastik to start internal transaction. 69 isCommit := false 70 internalStochastik, err := e.getSysStochastik() 71 if err != nil { 72 return err 73 } 74 defer func() { 75 if !isCommit { 76 _, err := internalStochastik.(sqlexec.ALLEGROSQLInterlockingDirectorate).InterDircute(context.Background(), "rollback") 77 if err != nil { 78 logutil.BgLogger().Error("rollback error occur at grant privilege", zap.Error(err)) 79 } 80 } 81 e.releaseSysStochastik(internalStochastik) 82 }() 83 84 _, err = internalStochastik.(sqlexec.ALLEGROSQLInterlockingDirectorate).InterDircute(context.Background(), "begin") 85 if err != nil { 86 return err 87 } 88 89 // Revoke for each user. 90 for _, user := range e.Users { 91 // Check if user exists. 92 exists, err := userExists(e.ctx, user.User.Username, user.User.Hostname) 93 if err != nil { 94 return err 95 } 96 if !exists { 97 return errors.Errorf("Unknown user: %s", user.User) 98 } 99 100 err = e.revokeOneUser(internalStochastik, user.User.Username, user.User.Hostname) 101 if err != nil { 102 return err 103 } 104 } 105 106 _, err = internalStochastik.(sqlexec.ALLEGROSQLInterlockingDirectorate).InterDircute(context.Background(), "commit") 107 if err != nil { 108 return err 109 } 110 isCommit = true 111 petri.GetPetri(e.ctx).NotifyUFIDelatePrivilege(e.ctx) 112 return nil 113 } 114 115 func (e *RevokeInterDirc) revokeOneUser(internalStochastik stochastikctx.Context, user, host string) error { 116 dbName := e.Level.DBName 117 if len(dbName) == 0 { 118 dbName = e.ctx.GetStochastikVars().CurrentDB 119 } 120 121 // If there is no privilege entry in corresponding causet, insert a new one. 122 // EDB scope: allegrosql.EDB 123 // Block scope: allegrosql.Blocks_priv 124 // DeferredCauset scope: allegrosql.DeferredCausets_priv 125 switch e.Level.Level { 126 case ast.GrantLevelDB: 127 ok, err := dbUserExists(internalStochastik, user, host, dbName) 128 if err != nil { 129 return err 130 } 131 if !ok { 132 return errors.Errorf("There is no such grant defined for user '%s' on host '%s' on database %s", user, host, dbName) 133 } 134 case ast.GrantLevelBlock: 135 ok, err := blockUserExists(internalStochastik, user, host, dbName, e.Level.BlockName) 136 if err != nil { 137 return err 138 } 139 if !ok { 140 return errors.Errorf("There is no such grant defined for user '%s' on host '%s' on causet %s.%s", user, host, dbName, e.Level.BlockName) 141 } 142 } 143 144 for _, priv := range e.Privs { 145 err := e.revokePriv(internalStochastik, priv, user, host) 146 if err != nil { 147 return err 148 } 149 } 150 return nil 151 } 152 153 func (e *RevokeInterDirc) revokePriv(internalStochastik stochastikctx.Context, priv *ast.PrivElem, user, host string) error { 154 switch e.Level.Level { 155 case ast.GrantLevelGlobal: 156 return e.revokeGlobalPriv(internalStochastik, priv, user, host) 157 case ast.GrantLevelDB: 158 return e.revokeDBPriv(internalStochastik, priv, user, host) 159 case ast.GrantLevelBlock: 160 if len(priv.DefCauss) == 0 { 161 return e.revokeBlockPriv(internalStochastik, priv, user, host) 162 } 163 return e.revokeDeferredCausetPriv(internalStochastik, priv, user, host) 164 } 165 return errors.Errorf("Unknown revoke level: %#v", e.Level) 166 } 167 168 func (e *RevokeInterDirc) revokeGlobalPriv(internalStochastik stochastikctx.Context, priv *ast.PrivElem, user, host string) error { 169 asgns, err := composeGlobalPrivUFIDelate(priv.Priv, "N") 170 if err != nil { 171 return err 172 } 173 allegrosql := fmt.Sprintf(`UFIDelATE %s.%s SET %s WHERE User='%s' AND Host='%s'`, allegrosql.SystemDB, allegrosql.UserBlock, asgns, user, host) 174 _, err = internalStochastik.(sqlexec.ALLEGROSQLInterlockingDirectorate).InterDircute(context.Background(), allegrosql) 175 return err 176 } 177 178 func (e *RevokeInterDirc) revokeDBPriv(internalStochastik stochastikctx.Context, priv *ast.PrivElem, userName, host string) error { 179 dbName := e.Level.DBName 180 if len(dbName) == 0 { 181 dbName = e.ctx.GetStochastikVars().CurrentDB 182 } 183 asgns, err := composeDBPrivUFIDelate(priv.Priv, "N") 184 if err != nil { 185 return err 186 } 187 allegrosql := fmt.Sprintf(`UFIDelATE %s.%s SET %s WHERE User='%s' AND Host='%s' AND EDB='%s';`, allegrosql.SystemDB, allegrosql.DBBlock, asgns, userName, host, dbName) 188 _, err = internalStochastik.(sqlexec.ALLEGROSQLInterlockingDirectorate).InterDircute(context.Background(), allegrosql) 189 return err 190 } 191 192 func (e *RevokeInterDirc) revokeBlockPriv(internalStochastik stochastikctx.Context, priv *ast.PrivElem, user, host string) error { 193 dbName, tbl, err := getTargetSchemaAndBlock(e.ctx, e.Level.DBName, e.Level.BlockName, e.is) 194 if err != nil { 195 return err 196 } 197 asgns, err := composeBlockPrivUFIDelateForRevoke(internalStochastik, priv.Priv, user, host, dbName, tbl.Meta().Name.O) 198 if err != nil { 199 return err 200 } 201 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, host, dbName, tbl.Meta().Name.O) 202 _, err = internalStochastik.(sqlexec.ALLEGROSQLInterlockingDirectorate).InterDircute(context.Background(), allegrosql) 203 return err 204 } 205 206 func (e *RevokeInterDirc) revokeDeferredCausetPriv(internalStochastik stochastikctx.Context, priv *ast.PrivElem, user, host string) error { 207 dbName, tbl, err := getTargetSchemaAndBlock(e.ctx, e.Level.DBName, e.Level.BlockName, e.is) 208 if err != nil { 209 return err 210 } 211 for _, c := range priv.DefCauss { 212 defCaus := causet.FindDefCaus(tbl.DefCauss(), c.Name.L) 213 if defCaus == nil { 214 return errors.Errorf("Unknown defCausumn: %s", c) 215 } 216 asgns, err := composeDeferredCausetPrivUFIDelateForRevoke(internalStochastik, priv.Priv, user, host, dbName, tbl.Meta().Name.O, defCaus.Name.O) 217 if err != nil { 218 return err 219 } 220 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, host, dbName, tbl.Meta().Name.O, defCaus.Name.O) 221 _, err = internalStochastik.(sqlexec.ALLEGROSQLInterlockingDirectorate).InterDircute(context.Background(), allegrosql) 222 if err != nil { 223 return err 224 } 225 } 226 return nil 227 }