From 6911511b51721ea2eef69f75dda4057c2c847ace Mon Sep 17 00:00:00 2001 From: Myzel394 <50424412+Myzel394@users.noreply.github.com> Date: Sat, 14 Sep 2024 22:37:56 +0200 Subject: [PATCH] feat(sshd_config): Parse match blocks inside the sshd_config parser --- handlers/sshd_config/ast/listener.go | 38 ++++++++++++++++++------- handlers/sshd_config/ast/parser_test.go | 34 +++++++++++++++------- handlers/sshd_config/ast/sshd_config.go | 2 ++ 3 files changed, 52 insertions(+), 22 deletions(-) diff --git a/handlers/sshd_config/ast/listener.go b/handlers/sshd_config/ast/listener.go index 2b3583c..be9b529 100644 --- a/handlers/sshd_config/ast/listener.go +++ b/handlers/sshd_config/ast/listener.go @@ -3,9 +3,11 @@ package ast import ( "config-lsp/common" "config-lsp/handlers/sshd_config/ast/parser" + match_parser "config-lsp/handlers/sshd_config/fields/match-parser" + "strings" + "github.com/emirpasic/gods/maps/treemap" gods "github.com/emirpasic/gods/utils" - "strings" ) type sshListenerContext struct { @@ -93,17 +95,31 @@ func (s *sshParserListener) ExitEntry(ctx *parser.EntryContext) { if s.sshContext.isKeyAMatchBlock { // Add new match block - matchBlock := &SSHMatchBlock{ - LocationRange: location, - MatchEntry: s.sshContext.currentOption, - Options: treemap.NewWith(gods.UInt32Comparator), - } - s.Config.Options.Put( - location.Start.Line, - matchBlock, - ) + match := match_parser.NewMatch() + errors := match.Parse(s.sshContext.currentOption.OptionValue.Value, location.Start.Line) + + if len(errors) > 0 { + for _, err := range errors { + s.Errors = append(s.Errors, common.LSPError{ + Range: err.Range.ShiftHorizontal(s.sshContext.currentOption.Start.Character), + Err: err.Err, + }) + } + } else { + matchBlock := &SSHMatchBlock{ + LocationRange: location, + MatchEntry: s.sshContext.currentOption, + MatchValue: match, + Options: treemap.NewWith(gods.UInt32Comparator), + } + s.Config.Options.Put( + location.Start.Line, + matchBlock, + ) + + s.sshContext.currentMatchBlock = matchBlock + } - s.sshContext.currentMatchBlock = matchBlock s.sshContext.isKeyAMatchBlock = false } else if s.sshContext.currentMatchBlock != nil { s.sshContext.currentMatchBlock.Options.Put( diff --git a/handlers/sshd_config/ast/parser_test.go b/handlers/sshd_config/ast/parser_test.go index 5077ac6..0061807 100644 --- a/handlers/sshd_config/ast/parser_test.go +++ b/handlers/sshd_config/ast/parser_test.go @@ -65,7 +65,7 @@ func TestMatchSimpleBlock( input := utils.Dedent(` PermitRootLogin no -Match 192.168.0.1 +Match Address 192.168.0.1 PasswordAuthentication yes `) p := NewSSHConfig() @@ -88,8 +88,12 @@ Match 192.168.0.1 rawSecondEntry, _ := p.Options.Get(uint32(2)) secondEntry := rawSecondEntry.(*SSHMatchBlock) - if !(secondEntry.MatchEntry.Value == "Match 192.168.0.1") { - t.Errorf("Expected second entry to be 'Match 192.168.0.1', but got: %v", secondEntry.MatchEntry.Value) + if !(secondEntry.MatchEntry.Value == "Match Address 192.168.0.1") { + t.Errorf("Expected second entry to be 'Match Address 192.168.0.1', but got: %v", secondEntry.MatchEntry.Value) + } + + if !(secondEntry.MatchValue.Entries[0].Criteria == "Address" && secondEntry.MatchValue.Entries[0].Values[0].Value == "192.168.0.1") { + t.Errorf("Expected second entry to be 'Match Address 192.168.0.1', but got: %v", secondEntry.MatchValue) } if !(secondEntry.Options.Size() == 1) { @@ -109,11 +113,11 @@ func TestMultipleMatchBlocks( input := utils.Dedent(` PermitRootLogin no -Match 192.168.0.1 +Match User lena PasswordAuthentication yes AllowUsers root user -Match 192.168.0.2 +Match Address 192.168.0.2 MaxAuthTries 3 `) p := NewSSHConfig() @@ -159,18 +163,18 @@ Match 192.168.0.2 } firstOption, firstMatchBlock := p.FindOption(uint32(3)) - if !(firstOption.Key.Value == "PasswordAuthentication" && firstOption.OptionValue.Value == "yes" && firstMatchBlock.MatchEntry.Value == "Match 192.168.0.1") { - t.Errorf("Expected first option to be 'PasswordAuthentication yes' and first match block to be 'Match 192.168.0.1', but got: %v, %v", firstOption, firstMatchBlock) + if !(firstOption.Key.Value == "PasswordAuthentication" && firstOption.OptionValue.Value == "yes") { + t.Errorf("Expected first option to be 'PasswordAuthentication yes' and first match block to be 'Match Address 192.168.0.1', but got: %v, %v", firstOption, firstMatchBlock) } emptyOption, matchBlock := p.FindOption(uint32(5)) - if !(emptyOption == nil && matchBlock.MatchEntry.Value == "Match 192.168.0.1") { - t.Errorf("Expected empty option and match block to be 'Match 192.168.0.1', but got: %v, %v", emptyOption, matchBlock) + if !(emptyOption == nil && matchBlock.MatchEntry.Value == "Match User lena" && matchBlock.MatchValue.Entries[0].Values[0].Value == "lena") { + t.Errorf("Expected empty option and match block to be 'Match User lena', but got: %v, %v", emptyOption, matchBlock) } matchOption, matchBlock := p.FindOption(uint32(2)) - if !(matchOption.Value == "Match 192.168.0.1" && matchBlock.MatchEntry.Value == "Match 192.168.0.1") { - t.Errorf("Expected match option to be 'Match 192.160.0.1' and match block to be 'Match 192.168.0.1', but got: %v, %v", matchOption, matchBlock) + if !(matchOption.Value == "Match User lena" && matchBlock.MatchEntry.Value == "Match User lena" && matchBlock.MatchValue.Entries[0].Values[0].Value == "lena") { + t.Errorf("Expected match option to be 'Match User lena', but got: %v, %v", matchOption, matchBlock) } } @@ -412,6 +416,10 @@ Match Address 172.22.100.0/24,172.22.5.0/24,127.0.0.1 t.Errorf("Expected fourth entry to be 'Match User anoncvs', but got: %v", fourthEntry.MatchEntry.Value) } + if !(fourthEntry.MatchValue.Entries[0].Criteria == "User" && fourthEntry.MatchValue.Entries[0].Values[0].Value == "anoncvs") { + t.Errorf("Expected fourth entry to be 'Match User anoncvs', but got: %v", fourthEntry.MatchValue) + } + if !(fourthEntry.Options.Size() == 3) { t.Errorf("Expected 3 options in fourth match block, but got: %v", fourthEntry.Options) } @@ -432,6 +440,10 @@ Match Address 172.22.100.0/24,172.22.5.0/24,127.0.0.1 t.Errorf("Expected sixth entry to be 'Match Address 172.22.100.0/24,172.22.5.0/24,127.0.0.1', but got: %v", sixthEntry.MatchEntry.Value) } + if !(sixthEntry.MatchValue.Entries[0].Criteria == "Address" && len(sixthEntry.MatchValue.Entries[0].Values) == 3) { + t.Errorf("Expected sixth entry to contain 3 values, but got: %v", sixthEntry.MatchValue) + } + if !(sixthEntry.Options.Size() == 2) { t.Errorf("Expected 2 options in sixth match block, but got: %v", sixthEntry.Options) } diff --git a/handlers/sshd_config/ast/sshd_config.go b/handlers/sshd_config/ast/sshd_config.go index f28c5d6..b448f63 100644 --- a/handlers/sshd_config/ast/sshd_config.go +++ b/handlers/sshd_config/ast/sshd_config.go @@ -2,6 +2,7 @@ package ast import ( "config-lsp/common" + match_parser "config-lsp/handlers/sshd_config/fields/match-parser" "github.com/emirpasic/gods/maps/treemap" ) @@ -52,6 +53,7 @@ func (o SSHOption) GetOption() SSHOption { type SSHMatchBlock struct { common.LocationRange MatchEntry *SSHOption + MatchValue *match_parser.Match // [uint32]*SSHOption -> line number -> *SSHOption Options *treemap.Map