mirror of
https://github.com/HeidiSQL/HeidiSQL.git
synced 2025-08-06 18:24:26 +08:00
Fix mixed up GRANT privilege in user manager, caused by errors and high complexity in regular expression. See issue #2671. Revert modification in SynRegExpr.pas again, now that we have only about 10 parentheses left.
This commit is contained in:
@ -161,7 +161,7 @@ const
|
|||||||
|
|
||||||
|
|
||||||
const
|
const
|
||||||
NSUBEXP = 30; // max number of subexpression //###0.929
|
NSUBEXP = 15; // max number of subexpression //###0.929
|
||||||
// Cannot be more than NSUBEXPMAX
|
// Cannot be more than NSUBEXPMAX
|
||||||
// Be carefull - don't use values which overflow CLOSE opcode
|
// Be carefull - don't use values which overflow CLOSE opcode
|
||||||
// (in this case you'll get compiler erorr).
|
// (in this case you'll get compiler erorr).
|
||||||
|
@ -439,7 +439,7 @@ var
|
|||||||
User: PUser;
|
User: PUser;
|
||||||
UserHost, RequireClause, WithClause: String;
|
UserHost, RequireClause, WithClause: String;
|
||||||
Grants, AllPNames, Cols: TStringList;
|
Grants, AllPNames, Cols: TStringList;
|
||||||
rxA, rxB: TRegExpr;
|
rxTemp, rxGrant: TRegExpr;
|
||||||
i, j: Integer;
|
i, j: Integer;
|
||||||
UserSelected: Boolean;
|
UserSelected: Boolean;
|
||||||
begin
|
begin
|
||||||
@ -487,43 +487,43 @@ begin
|
|||||||
end else
|
end else
|
||||||
Grants := FConnection.GetCol('SHOW GRANTS FOR '+esc(User.Username)+'@'+esc(User.Host));
|
Grants := FConnection.GetCol('SHOW GRANTS FOR '+esc(User.Username)+'@'+esc(User.Host));
|
||||||
|
|
||||||
rxA := TRegExpr.Create;
|
{ GRANT USAGE ON *.* TO 'newbie'@'%' IDENTIFIED BY PASSWORD '*99D8973ECC09819DF81624F051BFF4FC6695140B' REQUIRE (NONE | ssl_option [[AND] ssl_option] ...) WITH GRANT OPTION
|
||||||
rxA.ModifierI := True;
|
GRANT SELECT ON `avtoserver`.* TO 'newbie'@'%'
|
||||||
rxB := TRegExpr.Create;
|
GRANT SELECT, SELECT (Enter (column) name), INSERT, INSERT (Enter (column) name), UPDATE, UPDATE (Enter (column) name), DELETE, CREATE ON `avtoserver`.`avtomodel` TO 'newbie'@'%'
|
||||||
rxB.ModifierI := True;
|
GRANT EXECUTE, ALTER ROUTINE ON PROCEDURE `pulle`.`f_procedure` TO 'newbie'@'%' }
|
||||||
|
rxTemp := TRegExpr.Create;
|
||||||
|
rxTemp.ModifierI := True;
|
||||||
|
rxGrant := TRegExpr.Create;
|
||||||
|
rxGrant.ModifierI := True;
|
||||||
|
rxGrant.Expression := '^GRANT\s+(.+)\s+ON\s+((TABLE|FUNCTION|PROCEDURE)\s+)?`?([^`.]+)`?\.`?([^`]+)`?\s+TO\s+\S+(\s+IDENTIFIED\s+BY\s+(PASSWORD)?\s+''?([^'']+)''?)?(\s+REQUIRE\s+.+)?(\s+WITH\s+.+)?$';
|
||||||
|
|
||||||
for i:=0 to Grants.Count-1 do begin
|
for i:=0 to Grants.Count-1 do begin
|
||||||
// Find selected priv objects via regular expression
|
// Find selected priv objects via regular expression
|
||||||
{ GRANT USAGE ON *.* TO 'newbie'@'%' IDENTIFIED BY PASSWORD '*99D8973ECC09819DF81624F051BFF4FC6695140B' REQUIRE (NONE | ssl_option [[AND] ssl_option] ...) WITH GRANT OPTION
|
if rxGrant.Exec(Grants[i]) then begin
|
||||||
GRANT SELECT ON `avtoserver`.* TO 'newbie'@'%'
|
|
||||||
GRANT SELECT, SELECT (Enter (column) name), INSERT, INSERT (Enter (column) name), UPDATE, UPDATE (Enter (column) name), DELETE, CREATE ON `avtoserver`.`avtomodel` TO 'newbie'@'%'
|
|
||||||
GRANT EXECUTE, ALTER ROUTINE ON PROCEDURE `pulle`.`f_procedure` TO 'newbie'@'%' }
|
|
||||||
rxA.Expression := '^GRANT\s+(.+)\s+ON\s+((TABLE|FUNCTION|PROCEDURE)\s+)?`?([^`.]+)`?\.`?([^`]+)`?\s+TO\s+\S+(\s+IDENTIFIED\s+BY\s+(PASSWORD)?\s+''?([^'']+)''?)?(\s+REQUIRE\s+((NONE|SSL|X509|CIPHER|ISSUER|SUBJECT)(\s+''[^'']*'')?(\s+AND)?\s+)+)?(\s+WITH\s+GRANT\s+OPTION)?(.*)$';
|
|
||||||
if rxA.Exec(Grants[i]) then begin
|
|
||||||
P := TPrivObj.Create;
|
P := TPrivObj.Create;
|
||||||
P.GrantCode := Grants[i];
|
P.GrantCode := Grants[i];
|
||||||
P.Added := FAdded;
|
P.Added := FAdded;
|
||||||
FPrivObjects.Add(P);
|
FPrivObjects.Add(P);
|
||||||
|
|
||||||
if (rxA.Match[4] = '*') and (rxA.Match[5] = '*') then begin
|
if (rxGrant.Match[4] = '*') and (rxGrant.Match[5] = '*') then begin
|
||||||
P.DBObj.NodeType := lntNone;
|
P.DBObj.NodeType := lntNone;
|
||||||
P.AllPrivileges := PrivsGlobal;
|
P.AllPrivileges := PrivsGlobal;
|
||||||
if not FAdded then begin
|
if not FAdded then begin
|
||||||
editPassword.TextHint := FConnection.UnescapeString(rxA.Match[8]);
|
editPassword.TextHint := FConnection.UnescapeString(rxGrant.Match[8]);
|
||||||
// Set password for changed user, to silence the error message about invalid length
|
// Set password for changed user, to silence the error message about invalid length
|
||||||
User.Password := editPassword.TextHint;
|
User.Password := editPassword.TextHint;
|
||||||
end;
|
end;
|
||||||
end else if (rxA.Match[5] = '*') then begin
|
end else if (rxGrant.Match[5] = '*') then begin
|
||||||
P.DBObj.NodeType := lntDb;
|
P.DBObj.NodeType := lntDb;
|
||||||
P.DBObj.Database := rxA.Match[4];
|
P.DBObj.Database := rxGrant.Match[4];
|
||||||
P.AllPrivileges := PrivsDb;
|
P.AllPrivileges := PrivsDb;
|
||||||
end else begin
|
end else begin
|
||||||
P.DBObj.Database := rxA.Match[4];
|
P.DBObj.Database := rxGrant.Match[4];
|
||||||
P.DBObj.Name := rxA.Match[5];
|
P.DBObj.Name := rxGrant.Match[5];
|
||||||
if UpperCase(rxA.Match[3]) = 'FUNCTION' then begin
|
if UpperCase(rxGrant.Match[3]) = 'FUNCTION' then begin
|
||||||
P.DBObj.NodeType := lntFunction;
|
P.DBObj.NodeType := lntFunction;
|
||||||
P.AllPrivileges := PrivsRoutine;
|
P.AllPrivileges := PrivsRoutine;
|
||||||
end else if (UpperCase(rxA.Match[3]) = 'PROCEDURE') then begin
|
end else if (UpperCase(rxGrant.Match[3]) = 'PROCEDURE') then begin
|
||||||
P.DBObj.NodeType := lntProcedure;
|
P.DBObj.NodeType := lntProcedure;
|
||||||
P.AllPrivileges := PrivsRoutine;
|
P.AllPrivileges := PrivsRoutine;
|
||||||
end else begin
|
end else begin
|
||||||
@ -536,17 +536,17 @@ begin
|
|||||||
{ USAGE
|
{ USAGE
|
||||||
SELECT, SELECT (id, colname), INSERT, INSERT (id, colname), UPDATE, UPDATE (colname), DELETE, CREATE
|
SELECT, SELECT (id, colname), INSERT, INSERT (id, colname), UPDATE, UPDATE (colname), DELETE, CREATE
|
||||||
EXECUTE, ALTER ROUTINE }
|
EXECUTE, ALTER ROUTINE }
|
||||||
if rxA.Match[1] = 'ALL PRIVILEGES' then begin
|
if rxGrant.Match[1] = 'ALL PRIVILEGES' then begin
|
||||||
P.OrgPrivs.AddStrings(P.AllPrivileges);
|
P.OrgPrivs.AddStrings(P.AllPrivileges);
|
||||||
P.OrgPrivs.Delete(P.OrgPrivs.IndexOf('GRANT'));
|
P.OrgPrivs.Delete(P.OrgPrivs.IndexOf('GRANT'));
|
||||||
end else begin
|
end else begin
|
||||||
rxB.Expression := '\b('+ImplodeStr('|', AllPnames)+')(\s+\(([^\)]+)\))?,';
|
rxTemp.Expression := '\b('+ImplodeStr('|', AllPnames)+')(\s+\(([^\)]+)\))?,';
|
||||||
if rxB.Exec(rxA.Match[1]+',') then while True do begin
|
if rxTemp.Exec(rxGrant.Match[1]+',') then while True do begin
|
||||||
if rxB.Match[3] = '' then
|
if rxTemp.Match[3] = '' then
|
||||||
P.OrgPrivs.Add(rxB.Match[1])
|
P.OrgPrivs.Add(rxTemp.Match[1])
|
||||||
else begin
|
else begin
|
||||||
// Find previously created column priv or create new one
|
// Find previously created column priv or create new one
|
||||||
Cols := Explode(',', rxB.Match[3]);
|
Cols := Explode(',', rxTemp.Match[3]);
|
||||||
for j:=0 to Cols.Count-1 do begin
|
for j:=0 to Cols.Count-1 do begin
|
||||||
PCol := nil;
|
PCol := nil;
|
||||||
for Ptmp in FPrivObjects do begin
|
for Ptmp in FPrivObjects do begin
|
||||||
@ -567,39 +567,39 @@ begin
|
|||||||
PCol.AllPrivileges := PrivsColumn;
|
PCol.AllPrivileges := PrivsColumn;
|
||||||
FPrivObjects.Add(PCol);
|
FPrivObjects.Add(PCol);
|
||||||
end;
|
end;
|
||||||
PCol.OrgPrivs.Add(rxB.Match[1]);
|
PCol.OrgPrivs.Add(rxTemp.Match[1]);
|
||||||
PCol.GrantCode := PCol.GrantCode + rxB.Match[1] + ' ('+Trim(Cols[j])+')' + ', ';
|
PCol.GrantCode := PCol.GrantCode + rxTemp.Match[1] + ' ('+Trim(Cols[j])+')' + ', ';
|
||||||
end;
|
end;
|
||||||
|
|
||||||
end;
|
end;
|
||||||
if not rxB.ExecNext then
|
if not rxTemp.ExecNext then
|
||||||
break;
|
break;
|
||||||
end;
|
end;
|
||||||
|
|
||||||
end;
|
end;
|
||||||
|
|
||||||
// REQUIRE SSL X509 ISSUER '456' SUBJECT '789' CIPHER '123' NONE
|
// REQUIRE SSL X509 ISSUER '456' SUBJECT '789' CIPHER '123' NONE
|
||||||
RequireClause := rxA.Match[9];
|
if rxGrant.Match[9] <> '' then begin
|
||||||
if RequireClause <> '' then begin
|
RequireClause := rxGrant.Match[9];
|
||||||
User.SSL := 0;
|
User.SSL := 0;
|
||||||
User.Cipher := '';
|
User.Cipher := '';
|
||||||
User.Issuer := '';
|
User.Issuer := '';
|
||||||
User.Subject := '';
|
User.Subject := '';
|
||||||
rxB.Expression := '\bSSL\b';
|
rxTemp.Expression := '\bSSL\b';
|
||||||
if rxB.Exec(RequireClause) then
|
if rxTemp.Exec(RequireClause) then
|
||||||
User.SSL := 1;
|
User.SSL := 1;
|
||||||
rxB.Expression := '\bX509\b';
|
rxTemp.Expression := '\bX509\b';
|
||||||
if rxB.Exec(RequireClause) then
|
if rxTemp.Exec(RequireClause) then
|
||||||
User.SSL := 2;
|
User.SSL := 2;
|
||||||
rxB.Expression := '\bCIPHER\s+''([^'']+)';
|
rxTemp.Expression := '\bCIPHER\s+''([^'']+)';
|
||||||
if rxB.Exec(RequireClause) then
|
if rxTemp.Exec(RequireClause) then
|
||||||
User.Cipher := rxB.Match[1];
|
User.Cipher := rxTemp.Match[1];
|
||||||
rxB.Expression := '\bISSUER\s+''([^'']+)';
|
rxTemp.Expression := '\bISSUER\s+''([^'']+)';
|
||||||
if rxB.Exec(RequireClause) then
|
if rxTemp.Exec(RequireClause) then
|
||||||
User.Issuer := rxB.Match[1];
|
User.Issuer := rxTemp.Match[1];
|
||||||
rxB.Expression := '\bSUBJECT\s+''([^'']+)';
|
rxTemp.Expression := '\bSUBJECT\s+''([^'']+)';
|
||||||
if rxB.Exec(RequireClause) then
|
if rxTemp.Exec(RequireClause) then
|
||||||
User.Subject := rxB.Match[1];
|
User.Subject := rxTemp.Match[1];
|
||||||
if IsNotEmpty(User.Cipher) or IsNotEmpty(User.Issuer) or IsNotEmpty(User.Subject) then
|
if IsNotEmpty(User.Cipher) or IsNotEmpty(User.Issuer) or IsNotEmpty(User.Subject) then
|
||||||
User.SSL := 3;
|
User.SSL := 3;
|
||||||
comboSSL.ItemIndex := User.SSL;
|
comboSSL.ItemIndex := User.SSL;
|
||||||
@ -609,39 +609,36 @@ begin
|
|||||||
editSubject.Text := User.Subject;
|
editSubject.Text := User.Subject;
|
||||||
end;
|
end;
|
||||||
|
|
||||||
// WITH .. GRANT OPTION ?
|
// WITH .. GRANT OPTION
|
||||||
if rxA.Match[15] <> '' then
|
// MAX_QUERIES_PER_HOUR 20 MAX_UPDATES_PER_HOUR 10 MAX_CONNECTIONS_PER_HOUR 5 MAX_USER_CONNECTIONS 2
|
||||||
P.OrgPrivs.Add('GRANT');
|
if rxGrant.Match[10] <> '' then begin
|
||||||
if (P.OrgPrivs.Count = 0) and (P.DBObj.NodeType = lntTable) then
|
WithClause := rxGrant.Match[10];
|
||||||
FPrivObjects.Remove(P);
|
|
||||||
|
|
||||||
// WITH MAX_QUERIES_PER_HOUR 20
|
|
||||||
// MAX_UPDATES_PER_HOUR 10
|
|
||||||
// MAX_CONNECTIONS_PER_HOUR 5
|
|
||||||
// MAX_USER_CONNECTIONS 2;
|
|
||||||
WithClause := rxA.Match[16];
|
|
||||||
if WithClause <> '' then begin
|
|
||||||
User.MaxQueries := 0;
|
User.MaxQueries := 0;
|
||||||
User.MaxUpdates := 0;
|
User.MaxUpdates := 0;
|
||||||
User.MaxConnections := 0;
|
User.MaxConnections := 0;
|
||||||
User.MaxUserConnections := 0;
|
User.MaxUserConnections := 0;
|
||||||
rxB.Expression := '\bMAX_QUERIES_PER_HOUR\s+(\d+)\b';
|
if ExecRegExpr('\bGRANT\s+OPTION\b', WithClause) then
|
||||||
if rxB.Exec(WithClause) then
|
P.OrgPrivs.Add('GRANT');
|
||||||
User.MaxQueries := MakeInt(rxB.Match[1]);
|
rxTemp.Expression := '\bMAX_QUERIES_PER_HOUR\s+(\d+)\b';
|
||||||
rxB.Expression := '\bMAX_UPDATES_PER_HOUR\s+(\d+)\b';
|
if rxTemp.Exec(WithClause) then
|
||||||
if rxB.Exec(WithClause) then
|
User.MaxQueries := MakeInt(rxTemp.Match[1]);
|
||||||
User.MaxUpdates := MakeInt(rxB.Match[1]);
|
rxTemp.Expression := '\bMAX_UPDATES_PER_HOUR\s+(\d+)\b';
|
||||||
rxB.Expression := '\bMAX_CONNECTIONS_PER_HOUR\s+(\d+)\b';
|
if rxTemp.Exec(WithClause) then
|
||||||
if rxB.Exec(WithClause) then
|
User.MaxUpdates := MakeInt(rxTemp.Match[1]);
|
||||||
User.MaxConnections := MakeInt(rxB.Match[1]);
|
rxTemp.Expression := '\bMAX_CONNECTIONS_PER_HOUR\s+(\d+)\b';
|
||||||
rxB.Expression := '\bMAX_USER_CONNECTIONS\s+(\d+)\b';
|
if rxTemp.Exec(WithClause) then
|
||||||
if rxB.Exec(WithClause) then
|
User.MaxConnections := MakeInt(rxTemp.Match[1]);
|
||||||
User.MaxUserConnections := MakeInt(rxB.Match[1]);
|
rxTemp.Expression := '\bMAX_USER_CONNECTIONS\s+(\d+)\b';
|
||||||
|
if rxTemp.Exec(WithClause) then
|
||||||
|
User.MaxUserConnections := MakeInt(rxTemp.Match[1]);
|
||||||
udMaxQueries.Position := User.MaxQueries;
|
udMaxQueries.Position := User.MaxQueries;
|
||||||
udMaxUpdates.Position := User.MaxUpdates;
|
udMaxUpdates.Position := User.MaxUpdates;
|
||||||
udMaxConnections.Position := User.MaxConnections;
|
udMaxConnections.Position := User.MaxConnections;
|
||||||
udMaxUserConnections.Position := User.MaxUserConnections;
|
udMaxUserConnections.Position := User.MaxUserConnections;
|
||||||
end;
|
end;
|
||||||
|
|
||||||
|
if (P.OrgPrivs.Count = 0) and (P.DBObj.NodeType = lntTable) then
|
||||||
|
FPrivObjects.Remove(P);
|
||||||
end;
|
end;
|
||||||
end;
|
end;
|
||||||
|
|
||||||
@ -659,8 +656,8 @@ begin
|
|||||||
end;
|
end;
|
||||||
|
|
||||||
FPrivObjects.Sort;
|
FPrivObjects.Sort;
|
||||||
rxA.Free;
|
rxGrant.Free;
|
||||||
rxB.Free;
|
rxTemp.Free;
|
||||||
FreeAndNil(Grants);
|
FreeAndNil(Grants);
|
||||||
FreeAndNil(CloneGrants);
|
FreeAndNil(CloneGrants);
|
||||||
FreeAndNil(AllPnames);
|
FreeAndNil(AllPnames);
|
||||||
|
Reference in New Issue
Block a user