diff --git a/handlers/sshd_config/ast/listener.go b/handlers/sshd_config/ast/listener.go index e6d4b47..2b3583c 100644 --- a/handlers/sshd_config/ast/listener.go +++ b/handlers/sshd_config/ast/listener.go @@ -8,17 +8,6 @@ import ( "strings" ) -func createListener( - config *SSHConfig, - context *sshListenerContext, -) sshParserListener { - return sshParserListener{ - Config: config, - Errors: make([]common.LSPError, 0), - sshContext: context, - } -} - type sshListenerContext struct { line uint32 currentOption *SSHOption @@ -33,6 +22,17 @@ func createSSHListenerContext() *sshListenerContext { return context } +func createListener( + config *SSHConfig, + context *sshListenerContext, +) sshParserListener { + return sshParserListener{ + Config: config, + Errors: make([]common.LSPError, 0), + sshContext: context, + } +} + type sshParserListener struct { *parser.BaseConfigListener Config *SSHConfig diff --git a/handlers/sshd_config/fields/match-parser/Match.g4 b/handlers/sshd_config/fields/match-parser/Match.g4 new file mode 100644 index 0000000..9c2c54b --- /dev/null +++ b/handlers/sshd_config/fields/match-parser/Match.g4 @@ -0,0 +1,67 @@ +grammar Match; + +root + : matchEntry? (WHITESPACE matchEntry)* EOF + ; + +matchEntry + : criteria WHITESPACE? values? + ; + +criteria + : USER + | GROUP + | HOST + | LOCALADDRESS + | LOCALPORT + | RDOMAIN + | ADDRESS + ; + +values + : value? (COMMA value?)* + ; + +value + : STRING + ; + +USER + : ('U'|'u') ('S'|'s') ('E'|'e') ('R'|'r') + ; + +GROUP + : ('G'|'g') ('R'|'r') ('O'|'o') ('U'|'u') ('P'|'p') + ; + +HOST + : ('H'|'h') ('O'|'o') ('S'|'s') ('T'|'t') + ; + +LOCALADDRESS + : ('L'|'l') ('O'|'o') ('C'|'c') ('A'|'a') ('L'|'l') ('A'|'a') ('D'|'d') ('D'|'d') ('R'|'r') ('E'|'e') ('S'|'s') ('S'|'s') + ; + +LOCALPORT + : ('L'|'l') ('O'|'o') ('C'|'c') ('A'|'a') ('L'|'l') ('P'|'p') ('O'|'o') ('R'|'r') ('T'|'t') + ; + +RDOMAIN + : ('R'|'r') ('D'|'d') ('O'|'o') ('M'|'m') ('A'|'a') ('I'|'i') ('N'|'n') + ; + +ADDRESS + : ('A'|'a') ('D'|'d') ('D'|'d') ('R'|'r') ('E'|'e') ('S'|'s') ('S'|'s') + ; + +COMMA + : ',' + ; + +STRING + : ~(' ' | '\t' | '\r' | '\n' | '#' | ',')+ + ; + +WHITESPACE + : [ \t]+ + ; diff --git a/handlers/sshd_config/fields/match-parser/error-listener.go b/handlers/sshd_config/fields/match-parser/error-listener.go new file mode 100644 index 0000000..fd9e4bb --- /dev/null +++ b/handlers/sshd_config/fields/match-parser/error-listener.go @@ -0,0 +1,45 @@ +package match_parser + +import ( + "config-lsp/common" + + "github.com/antlr4-go/antlr/v4" +) + +type errorListenerContext struct { + line uint32 +} + +func createErrorListener( + line uint32, +) errorListener { + return errorListener{ + Errors: make([]common.LSPError, 0), + context: errorListenerContext{ + line: line, + }, + } +} + +type errorListener struct { + *antlr.DefaultErrorListener + Errors []common.LSPError + context errorListenerContext +} + +func (d *errorListener) SyntaxError( + recognizer antlr.Recognizer, + offendingSymbol interface{}, + _ int, + character int, + message string, + error antlr.RecognitionException, +) { + line := d.context.line + d.Errors = append(d.Errors, common.LSPError{ + Range: common.CreateSingleCharRange(uint32(line), uint32(character)), + Err: common.SyntaxError{ + Message: message, + }, + }) +} diff --git a/handlers/sshd_config/fields/match-parser/listener.go b/handlers/sshd_config/fields/match-parser/listener.go new file mode 100644 index 0000000..a7ca5ac --- /dev/null +++ b/handlers/sshd_config/fields/match-parser/listener.go @@ -0,0 +1,99 @@ +package match_parser + +import ( + "config-lsp/common" + "config-lsp/handlers/sshd_config/fields/match-parser/parser" + "config-lsp/utils" + "errors" + "fmt" + "strings" +) + +func createMatchListenerContext( + line uint32, +) *matchListenerContext { + return &matchListenerContext{ + currentEntry: nil, + line: line, + } +} + +type matchListenerContext struct { + currentEntry *MatchEntry + line uint32 +} + +func createListener( + match *Match, + context *matchListenerContext, +) matchParserListener { + return matchParserListener{ + match: match, + Errors: make([]common.LSPError, 0), + matchContext: context, + } +} + +type matchParserListener struct { + *parser.BaseMatchListener + match *Match + Errors []common.LSPError + matchContext *matchListenerContext +} + +func (s *matchParserListener) EnterMatchEntry(ctx *parser.MatchEntryContext) { + location := common.CharacterRangeFromCtx(ctx.BaseParserRuleContext) + location.ChangeBothLines(s.matchContext.line) + + entry := &MatchEntry{ + LocationRange: location, + Value: ctx.GetText(), + Values: make([]*MatchValue, 0), + } + + s.match.Entries = append(s.match.Entries, entry) + s.matchContext.currentEntry = entry +} + +func (s *matchParserListener) ExitMatchEntry(ctx *parser.MatchEntryContext) { + s.matchContext.currentEntry = nil +} + +var availableCriteria = map[string]MatchCriteriaType{ + string(MatchCriteriaTypeUser): MatchCriteriaTypeUser, + string(MatchCriteriaTypeGroup): MatchCriteriaTypeGroup, + string(MatchCriteriaTypeHost): MatchCriteriaTypeHost, + string(MatchCriteriaTypeLocalAddress): MatchCriteriaTypeLocalAddress, + string(MatchCriteriaTypeLocalPort): MatchCriteriaTypeLocalPort, + string(MatchCriteriaTypeRDomain): MatchCriteriaTypeRDomain, + string(MatchCriteriaTypeAddress): MatchCriteriaTypeAddress, +} + +func (s *matchParserListener) EnterCriteria(ctx *parser.CriteriaContext) { + location := common.CharacterRangeFromCtx(ctx.BaseParserRuleContext) + location.ChangeBothLines(s.matchContext.line) + + criteria, found := availableCriteria[ctx.GetText()] + + if !found { + s.Errors = append(s.Errors, common.LSPError{ + Range: location, + Err: errors.New(fmt.Sprintf("Unknown criteria: %s; It must be one of: %s", ctx.GetText(), strings.Join(utils.KeysOfMap(availableCriteria), ", "))), + }) + return + } + + s.matchContext.currentEntry.Criteria = criteria +} + +func (s *matchParserListener) EnterValue(ctx *parser.ValueContext) { + location := common.CharacterRangeFromCtx(ctx.BaseParserRuleContext) + location.ChangeBothLines(s.matchContext.line) + + value := &MatchValue{ + LocationRange: location, + Value: ctx.GetText(), + } + + s.matchContext.currentEntry.Values = append(s.matchContext.currentEntry.Values, value) +} diff --git a/handlers/sshd_config/fields/match-parser/match_ast.go b/handlers/sshd_config/fields/match-parser/match_ast.go new file mode 100644 index 0000000..2f97f1f --- /dev/null +++ b/handlers/sshd_config/fields/match-parser/match_ast.go @@ -0,0 +1,40 @@ +package match_parser + +import ( + "config-lsp/common" +) + +type Match struct { + Entries []*MatchEntry +} + +type MatchCriteriaType string + +const ( + MatchCriteriaTypeUser MatchCriteriaType = "User" + MatchCriteriaTypeGroup MatchCriteriaType = "Group" + MatchCriteriaTypeHost MatchCriteriaType = "Host" + MatchCriteriaTypeLocalAddress MatchCriteriaType = "LocalAddress" + MatchCriteriaTypeLocalPort MatchCriteriaType = "LocalPort" + MatchCriteriaTypeRDomain MatchCriteriaType = "RDomain" + MatchCriteriaTypeAddress MatchCriteriaType = "Address" +) + +type MatchCriteria struct { + common.LocationRange + + Type MatchCriteriaType +} + +type MatchEntry struct { + common.LocationRange + Value string + + Criteria MatchCriteriaType + Values []*MatchValue +} + +type MatchValue struct { + common.LocationRange + Value string +} diff --git a/handlers/sshd_config/fields/match-parser/parser.go b/handlers/sshd_config/fields/match-parser/parser.go new file mode 100644 index 0000000..96fe394 --- /dev/null +++ b/handlers/sshd_config/fields/match-parser/parser.go @@ -0,0 +1,52 @@ +package match_parser + +import ( + "config-lsp/common" + "config-lsp/handlers/sshd_config/fields/match-parser/parser" + "github.com/antlr4-go/antlr/v4" +) + +func NewMatch() *Match { + match := new(Match) + match.Clear() + + return match +} + +func (m *Match) Clear() { + m.Entries = make([]*MatchEntry, 0) +} + +func (m *Match) Parse( + input string, + line uint32, +) []common.LSPError { + context := createMatchListenerContext(line) + + stream := antlr.NewInputStream(input) + + lexerErrorListener := createErrorListener(context.line) + lexer := parser.NewMatchLexer(stream) + lexer.RemoveErrorListeners() + lexer.AddErrorListener(&lexerErrorListener) + + tokenStream := antlr.NewCommonTokenStream(lexer, antlr.TokenDefaultChannel) + + parserErrorListener := createErrorListener(context.line) + antlrParser := parser.NewMatchParser(tokenStream) + antlrParser.RemoveErrorListeners() + antlrParser.AddErrorListener(&parserErrorListener) + + listener := createListener(m, context) + antlr.ParseTreeWalkerDefault.Walk( + &listener, + antlrParser.Root(), + ) + + errors := lexerErrorListener.Errors + errors = append(errors, parserErrorListener.Errors...) + errors = append(errors, listener.Errors...) + + return errors + +} diff --git a/handlers/sshd_config/fields/match-parser/parser/Match.interp b/handlers/sshd_config/fields/match-parser/parser/Match.interp new file mode 100644 index 0000000..274d459 --- /dev/null +++ b/handlers/sshd_config/fields/match-parser/parser/Match.interp @@ -0,0 +1,36 @@ +token literal names: +null +null +null +null +null +null +null +null +',' +null +null + +token symbolic names: +null +USER +GROUP +HOST +LOCALADDRESS +LOCALPORT +RDOMAIN +ADDRESS +COMMA +STRING +WHITESPACE + +rule names: +root +matchEntry +criteria +values +value + + +atn: +[4, 1, 10, 46, 2, 0, 7, 0, 2, 1, 7, 1, 2, 2, 7, 2, 2, 3, 7, 3, 2, 4, 7, 4, 1, 0, 3, 0, 12, 8, 0, 1, 0, 1, 0, 5, 0, 16, 8, 0, 10, 0, 12, 0, 19, 9, 0, 1, 0, 1, 0, 1, 1, 1, 1, 3, 1, 25, 8, 1, 1, 1, 3, 1, 28, 8, 1, 1, 2, 1, 2, 1, 3, 3, 3, 33, 8, 3, 1, 3, 1, 3, 3, 3, 37, 8, 3, 5, 3, 39, 8, 3, 10, 3, 12, 3, 42, 9, 3, 1, 4, 1, 4, 1, 4, 0, 0, 5, 0, 2, 4, 6, 8, 0, 1, 1, 0, 1, 7, 47, 0, 11, 1, 0, 0, 0, 2, 22, 1, 0, 0, 0, 4, 29, 1, 0, 0, 0, 6, 32, 1, 0, 0, 0, 8, 43, 1, 0, 0, 0, 10, 12, 3, 2, 1, 0, 11, 10, 1, 0, 0, 0, 11, 12, 1, 0, 0, 0, 12, 17, 1, 0, 0, 0, 13, 14, 5, 10, 0, 0, 14, 16, 3, 2, 1, 0, 15, 13, 1, 0, 0, 0, 16, 19, 1, 0, 0, 0, 17, 15, 1, 0, 0, 0, 17, 18, 1, 0, 0, 0, 18, 20, 1, 0, 0, 0, 19, 17, 1, 0, 0, 0, 20, 21, 5, 0, 0, 1, 21, 1, 1, 0, 0, 0, 22, 24, 3, 4, 2, 0, 23, 25, 5, 10, 0, 0, 24, 23, 1, 0, 0, 0, 24, 25, 1, 0, 0, 0, 25, 27, 1, 0, 0, 0, 26, 28, 3, 6, 3, 0, 27, 26, 1, 0, 0, 0, 27, 28, 1, 0, 0, 0, 28, 3, 1, 0, 0, 0, 29, 30, 7, 0, 0, 0, 30, 5, 1, 0, 0, 0, 31, 33, 3, 8, 4, 0, 32, 31, 1, 0, 0, 0, 32, 33, 1, 0, 0, 0, 33, 40, 1, 0, 0, 0, 34, 36, 5, 8, 0, 0, 35, 37, 3, 8, 4, 0, 36, 35, 1, 0, 0, 0, 36, 37, 1, 0, 0, 0, 37, 39, 1, 0, 0, 0, 38, 34, 1, 0, 0, 0, 39, 42, 1, 0, 0, 0, 40, 38, 1, 0, 0, 0, 40, 41, 1, 0, 0, 0, 41, 7, 1, 0, 0, 0, 42, 40, 1, 0, 0, 0, 43, 44, 5, 9, 0, 0, 44, 9, 1, 0, 0, 0, 7, 11, 17, 24, 27, 32, 36, 40] \ No newline at end of file diff --git a/handlers/sshd_config/fields/match-parser/parser/Match.tokens b/handlers/sshd_config/fields/match-parser/parser/Match.tokens new file mode 100644 index 0000000..21f2b73 --- /dev/null +++ b/handlers/sshd_config/fields/match-parser/parser/Match.tokens @@ -0,0 +1,11 @@ +USER=1 +GROUP=2 +HOST=3 +LOCALADDRESS=4 +LOCALPORT=5 +RDOMAIN=6 +ADDRESS=7 +COMMA=8 +STRING=9 +WHITESPACE=10 +','=8 diff --git a/handlers/sshd_config/fields/match-parser/parser/MatchLexer.interp b/handlers/sshd_config/fields/match-parser/parser/MatchLexer.interp new file mode 100644 index 0000000..590b1bb --- /dev/null +++ b/handlers/sshd_config/fields/match-parser/parser/MatchLexer.interp @@ -0,0 +1,47 @@ +token literal names: +null +null +null +null +null +null +null +null +',' +null +null + +token symbolic names: +null +USER +GROUP +HOST +LOCALADDRESS +LOCALPORT +RDOMAIN +ADDRESS +COMMA +STRING +WHITESPACE + +rule names: +USER +GROUP +HOST +LOCALADDRESS +LOCALPORT +RDOMAIN +ADDRESS +COMMA +STRING +WHITESPACE + +channel names: +DEFAULT_TOKEN_CHANNEL +HIDDEN + +mode names: +DEFAULT_MODE + +atn: +[4, 0, 10, 88, 6, -1, 2, 0, 7, 0, 2, 1, 7, 1, 2, 2, 7, 2, 2, 3, 7, 3, 2, 4, 7, 4, 2, 5, 7, 5, 2, 6, 7, 6, 2, 7, 7, 7, 2, 8, 7, 8, 2, 9, 7, 9, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 2, 1, 2, 1, 2, 1, 2, 1, 2, 1, 3, 1, 3, 1, 3, 1, 3, 1, 3, 1, 3, 1, 3, 1, 3, 1, 3, 1, 3, 1, 3, 1, 3, 1, 3, 1, 4, 1, 4, 1, 4, 1, 4, 1, 4, 1, 4, 1, 4, 1, 4, 1, 4, 1, 4, 1, 5, 1, 5, 1, 5, 1, 5, 1, 5, 1, 5, 1, 5, 1, 5, 1, 6, 1, 6, 1, 6, 1, 6, 1, 6, 1, 6, 1, 6, 1, 6, 1, 7, 1, 7, 1, 8, 4, 8, 80, 8, 8, 11, 8, 12, 8, 81, 1, 9, 4, 9, 85, 8, 9, 11, 9, 12, 9, 86, 0, 0, 10, 1, 1, 3, 2, 5, 3, 7, 4, 9, 5, 11, 6, 13, 7, 15, 8, 17, 9, 19, 10, 1, 0, 18, 2, 0, 85, 85, 117, 117, 2, 0, 83, 83, 115, 115, 2, 0, 69, 69, 101, 101, 2, 0, 82, 82, 114, 114, 2, 0, 71, 71, 103, 103, 2, 0, 79, 79, 111, 111, 2, 0, 80, 80, 112, 112, 2, 0, 72, 72, 104, 104, 2, 0, 84, 84, 116, 116, 2, 0, 76, 76, 108, 108, 2, 0, 67, 67, 99, 99, 2, 0, 65, 65, 97, 97, 2, 0, 68, 68, 100, 100, 2, 0, 77, 77, 109, 109, 2, 0, 73, 73, 105, 105, 2, 0, 78, 78, 110, 110, 5, 0, 9, 10, 13, 13, 32, 32, 35, 35, 44, 44, 2, 0, 9, 9, 32, 32, 89, 0, 1, 1, 0, 0, 0, 0, 3, 1, 0, 0, 0, 0, 5, 1, 0, 0, 0, 0, 7, 1, 0, 0, 0, 0, 9, 1, 0, 0, 0, 0, 11, 1, 0, 0, 0, 0, 13, 1, 0, 0, 0, 0, 15, 1, 0, 0, 0, 0, 17, 1, 0, 0, 0, 0, 19, 1, 0, 0, 0, 1, 21, 1, 0, 0, 0, 3, 26, 1, 0, 0, 0, 5, 32, 1, 0, 0, 0, 7, 37, 1, 0, 0, 0, 9, 50, 1, 0, 0, 0, 11, 60, 1, 0, 0, 0, 13, 68, 1, 0, 0, 0, 15, 76, 1, 0, 0, 0, 17, 79, 1, 0, 0, 0, 19, 84, 1, 0, 0, 0, 21, 22, 7, 0, 0, 0, 22, 23, 7, 1, 0, 0, 23, 24, 7, 2, 0, 0, 24, 25, 7, 3, 0, 0, 25, 2, 1, 0, 0, 0, 26, 27, 7, 4, 0, 0, 27, 28, 7, 3, 0, 0, 28, 29, 7, 5, 0, 0, 29, 30, 7, 0, 0, 0, 30, 31, 7, 6, 0, 0, 31, 4, 1, 0, 0, 0, 32, 33, 7, 7, 0, 0, 33, 34, 7, 5, 0, 0, 34, 35, 7, 1, 0, 0, 35, 36, 7, 8, 0, 0, 36, 6, 1, 0, 0, 0, 37, 38, 7, 9, 0, 0, 38, 39, 7, 5, 0, 0, 39, 40, 7, 10, 0, 0, 40, 41, 7, 11, 0, 0, 41, 42, 7, 9, 0, 0, 42, 43, 7, 11, 0, 0, 43, 44, 7, 12, 0, 0, 44, 45, 7, 12, 0, 0, 45, 46, 7, 3, 0, 0, 46, 47, 7, 2, 0, 0, 47, 48, 7, 1, 0, 0, 48, 49, 7, 1, 0, 0, 49, 8, 1, 0, 0, 0, 50, 51, 7, 9, 0, 0, 51, 52, 7, 5, 0, 0, 52, 53, 7, 10, 0, 0, 53, 54, 7, 11, 0, 0, 54, 55, 7, 9, 0, 0, 55, 56, 7, 6, 0, 0, 56, 57, 7, 5, 0, 0, 57, 58, 7, 3, 0, 0, 58, 59, 7, 8, 0, 0, 59, 10, 1, 0, 0, 0, 60, 61, 7, 3, 0, 0, 61, 62, 7, 12, 0, 0, 62, 63, 7, 5, 0, 0, 63, 64, 7, 13, 0, 0, 64, 65, 7, 11, 0, 0, 65, 66, 7, 14, 0, 0, 66, 67, 7, 15, 0, 0, 67, 12, 1, 0, 0, 0, 68, 69, 7, 11, 0, 0, 69, 70, 7, 12, 0, 0, 70, 71, 7, 12, 0, 0, 71, 72, 7, 3, 0, 0, 72, 73, 7, 2, 0, 0, 73, 74, 7, 1, 0, 0, 74, 75, 7, 1, 0, 0, 75, 14, 1, 0, 0, 0, 76, 77, 5, 44, 0, 0, 77, 16, 1, 0, 0, 0, 78, 80, 8, 16, 0, 0, 79, 78, 1, 0, 0, 0, 80, 81, 1, 0, 0, 0, 81, 79, 1, 0, 0, 0, 81, 82, 1, 0, 0, 0, 82, 18, 1, 0, 0, 0, 83, 85, 7, 17, 0, 0, 84, 83, 1, 0, 0, 0, 85, 86, 1, 0, 0, 0, 86, 84, 1, 0, 0, 0, 86, 87, 1, 0, 0, 0, 87, 20, 1, 0, 0, 0, 3, 0, 81, 86, 0] \ No newline at end of file diff --git a/handlers/sshd_config/fields/match-parser/parser/MatchLexer.tokens b/handlers/sshd_config/fields/match-parser/parser/MatchLexer.tokens new file mode 100644 index 0000000..21f2b73 --- /dev/null +++ b/handlers/sshd_config/fields/match-parser/parser/MatchLexer.tokens @@ -0,0 +1,11 @@ +USER=1 +GROUP=2 +HOST=3 +LOCALADDRESS=4 +LOCALPORT=5 +RDOMAIN=6 +ADDRESS=7 +COMMA=8 +STRING=9 +WHITESPACE=10 +','=8 diff --git a/handlers/sshd_config/fields/match-parser/parser/match_base_listener.go b/handlers/sshd_config/fields/match-parser/parser/match_base_listener.go new file mode 100644 index 0000000..2190a4a --- /dev/null +++ b/handlers/sshd_config/fields/match-parser/parser/match_base_listener.go @@ -0,0 +1,52 @@ +// Code generated from Match.g4 by ANTLR 4.13.0. DO NOT EDIT. + +package parser // Match + +import "github.com/antlr4-go/antlr/v4" + +// BaseMatchListener is a complete listener for a parse tree produced by MatchParser. +type BaseMatchListener struct{} + +var _ MatchListener = &BaseMatchListener{} + +// VisitTerminal is called when a terminal node is visited. +func (s *BaseMatchListener) VisitTerminal(node antlr.TerminalNode) {} + +// VisitErrorNode is called when an error node is visited. +func (s *BaseMatchListener) VisitErrorNode(node antlr.ErrorNode) {} + +// EnterEveryRule is called when any rule is entered. +func (s *BaseMatchListener) EnterEveryRule(ctx antlr.ParserRuleContext) {} + +// ExitEveryRule is called when any rule is exited. +func (s *BaseMatchListener) ExitEveryRule(ctx antlr.ParserRuleContext) {} + +// EnterRoot is called when production root is entered. +func (s *BaseMatchListener) EnterRoot(ctx *RootContext) {} + +// ExitRoot is called when production root is exited. +func (s *BaseMatchListener) ExitRoot(ctx *RootContext) {} + +// EnterMatchEntry is called when production matchEntry is entered. +func (s *BaseMatchListener) EnterMatchEntry(ctx *MatchEntryContext) {} + +// ExitMatchEntry is called when production matchEntry is exited. +func (s *BaseMatchListener) ExitMatchEntry(ctx *MatchEntryContext) {} + +// EnterCriteria is called when production criteria is entered. +func (s *BaseMatchListener) EnterCriteria(ctx *CriteriaContext) {} + +// ExitCriteria is called when production criteria is exited. +func (s *BaseMatchListener) ExitCriteria(ctx *CriteriaContext) {} + +// EnterValues is called when production values is entered. +func (s *BaseMatchListener) EnterValues(ctx *ValuesContext) {} + +// ExitValues is called when production values is exited. +func (s *BaseMatchListener) ExitValues(ctx *ValuesContext) {} + +// EnterValue is called when production value is entered. +func (s *BaseMatchListener) EnterValue(ctx *ValueContext) {} + +// ExitValue is called when production value is exited. +func (s *BaseMatchListener) ExitValue(ctx *ValueContext) {} diff --git a/handlers/sshd_config/fields/match-parser/parser/match_lexer.go b/handlers/sshd_config/fields/match-parser/parser/match_lexer.go new file mode 100644 index 0000000..0c61e79 --- /dev/null +++ b/handlers/sshd_config/fields/match-parser/parser/match_lexer.go @@ -0,0 +1,148 @@ +// Code generated from Match.g4 by ANTLR 4.13.0. DO NOT EDIT. + +package parser + +import ( + "fmt" + "github.com/antlr4-go/antlr/v4" + "sync" + "unicode" +) + +// Suppress unused import error +var _ = fmt.Printf +var _ = sync.Once{} +var _ = unicode.IsLetter + +type MatchLexer struct { + *antlr.BaseLexer + channelNames []string + modeNames []string + // TODO: EOF string +} + +var MatchLexerLexerStaticData struct { + once sync.Once + serializedATN []int32 + ChannelNames []string + ModeNames []string + LiteralNames []string + SymbolicNames []string + RuleNames []string + PredictionContextCache *antlr.PredictionContextCache + atn *antlr.ATN + decisionToDFA []*antlr.DFA +} + +func matchlexerLexerInit() { + staticData := &MatchLexerLexerStaticData + staticData.ChannelNames = []string{ + "DEFAULT_TOKEN_CHANNEL", "HIDDEN", + } + staticData.ModeNames = []string{ + "DEFAULT_MODE", + } + staticData.LiteralNames = []string{ + "", "", "", "", "", "", "", "", "','", + } + staticData.SymbolicNames = []string{ + "", "USER", "GROUP", "HOST", "LOCALADDRESS", "LOCALPORT", "RDOMAIN", + "ADDRESS", "COMMA", "STRING", "WHITESPACE", + } + staticData.RuleNames = []string{ + "USER", "GROUP", "HOST", "LOCALADDRESS", "LOCALPORT", "RDOMAIN", "ADDRESS", + "COMMA", "STRING", "WHITESPACE", + } + staticData.PredictionContextCache = antlr.NewPredictionContextCache() + staticData.serializedATN = []int32{ + 4, 0, 10, 88, 6, -1, 2, 0, 7, 0, 2, 1, 7, 1, 2, 2, 7, 2, 2, 3, 7, 3, 2, + 4, 7, 4, 2, 5, 7, 5, 2, 6, 7, 6, 2, 7, 7, 7, 2, 8, 7, 8, 2, 9, 7, 9, 1, + 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 2, 1, + 2, 1, 2, 1, 2, 1, 2, 1, 3, 1, 3, 1, 3, 1, 3, 1, 3, 1, 3, 1, 3, 1, 3, 1, + 3, 1, 3, 1, 3, 1, 3, 1, 3, 1, 4, 1, 4, 1, 4, 1, 4, 1, 4, 1, 4, 1, 4, 1, + 4, 1, 4, 1, 4, 1, 5, 1, 5, 1, 5, 1, 5, 1, 5, 1, 5, 1, 5, 1, 5, 1, 6, 1, + 6, 1, 6, 1, 6, 1, 6, 1, 6, 1, 6, 1, 6, 1, 7, 1, 7, 1, 8, 4, 8, 80, 8, 8, + 11, 8, 12, 8, 81, 1, 9, 4, 9, 85, 8, 9, 11, 9, 12, 9, 86, 0, 0, 10, 1, + 1, 3, 2, 5, 3, 7, 4, 9, 5, 11, 6, 13, 7, 15, 8, 17, 9, 19, 10, 1, 0, 18, + 2, 0, 85, 85, 117, 117, 2, 0, 83, 83, 115, 115, 2, 0, 69, 69, 101, 101, + 2, 0, 82, 82, 114, 114, 2, 0, 71, 71, 103, 103, 2, 0, 79, 79, 111, 111, + 2, 0, 80, 80, 112, 112, 2, 0, 72, 72, 104, 104, 2, 0, 84, 84, 116, 116, + 2, 0, 76, 76, 108, 108, 2, 0, 67, 67, 99, 99, 2, 0, 65, 65, 97, 97, 2, + 0, 68, 68, 100, 100, 2, 0, 77, 77, 109, 109, 2, 0, 73, 73, 105, 105, 2, + 0, 78, 78, 110, 110, 5, 0, 9, 10, 13, 13, 32, 32, 35, 35, 44, 44, 2, 0, + 9, 9, 32, 32, 89, 0, 1, 1, 0, 0, 0, 0, 3, 1, 0, 0, 0, 0, 5, 1, 0, 0, 0, + 0, 7, 1, 0, 0, 0, 0, 9, 1, 0, 0, 0, 0, 11, 1, 0, 0, 0, 0, 13, 1, 0, 0, + 0, 0, 15, 1, 0, 0, 0, 0, 17, 1, 0, 0, 0, 0, 19, 1, 0, 0, 0, 1, 21, 1, 0, + 0, 0, 3, 26, 1, 0, 0, 0, 5, 32, 1, 0, 0, 0, 7, 37, 1, 0, 0, 0, 9, 50, 1, + 0, 0, 0, 11, 60, 1, 0, 0, 0, 13, 68, 1, 0, 0, 0, 15, 76, 1, 0, 0, 0, 17, + 79, 1, 0, 0, 0, 19, 84, 1, 0, 0, 0, 21, 22, 7, 0, 0, 0, 22, 23, 7, 1, 0, + 0, 23, 24, 7, 2, 0, 0, 24, 25, 7, 3, 0, 0, 25, 2, 1, 0, 0, 0, 26, 27, 7, + 4, 0, 0, 27, 28, 7, 3, 0, 0, 28, 29, 7, 5, 0, 0, 29, 30, 7, 0, 0, 0, 30, + 31, 7, 6, 0, 0, 31, 4, 1, 0, 0, 0, 32, 33, 7, 7, 0, 0, 33, 34, 7, 5, 0, + 0, 34, 35, 7, 1, 0, 0, 35, 36, 7, 8, 0, 0, 36, 6, 1, 0, 0, 0, 37, 38, 7, + 9, 0, 0, 38, 39, 7, 5, 0, 0, 39, 40, 7, 10, 0, 0, 40, 41, 7, 11, 0, 0, + 41, 42, 7, 9, 0, 0, 42, 43, 7, 11, 0, 0, 43, 44, 7, 12, 0, 0, 44, 45, 7, + 12, 0, 0, 45, 46, 7, 3, 0, 0, 46, 47, 7, 2, 0, 0, 47, 48, 7, 1, 0, 0, 48, + 49, 7, 1, 0, 0, 49, 8, 1, 0, 0, 0, 50, 51, 7, 9, 0, 0, 51, 52, 7, 5, 0, + 0, 52, 53, 7, 10, 0, 0, 53, 54, 7, 11, 0, 0, 54, 55, 7, 9, 0, 0, 55, 56, + 7, 6, 0, 0, 56, 57, 7, 5, 0, 0, 57, 58, 7, 3, 0, 0, 58, 59, 7, 8, 0, 0, + 59, 10, 1, 0, 0, 0, 60, 61, 7, 3, 0, 0, 61, 62, 7, 12, 0, 0, 62, 63, 7, + 5, 0, 0, 63, 64, 7, 13, 0, 0, 64, 65, 7, 11, 0, 0, 65, 66, 7, 14, 0, 0, + 66, 67, 7, 15, 0, 0, 67, 12, 1, 0, 0, 0, 68, 69, 7, 11, 0, 0, 69, 70, 7, + 12, 0, 0, 70, 71, 7, 12, 0, 0, 71, 72, 7, 3, 0, 0, 72, 73, 7, 2, 0, 0, + 73, 74, 7, 1, 0, 0, 74, 75, 7, 1, 0, 0, 75, 14, 1, 0, 0, 0, 76, 77, 5, + 44, 0, 0, 77, 16, 1, 0, 0, 0, 78, 80, 8, 16, 0, 0, 79, 78, 1, 0, 0, 0, + 80, 81, 1, 0, 0, 0, 81, 79, 1, 0, 0, 0, 81, 82, 1, 0, 0, 0, 82, 18, 1, + 0, 0, 0, 83, 85, 7, 17, 0, 0, 84, 83, 1, 0, 0, 0, 85, 86, 1, 0, 0, 0, 86, + 84, 1, 0, 0, 0, 86, 87, 1, 0, 0, 0, 87, 20, 1, 0, 0, 0, 3, 0, 81, 86, 0, + } + deserializer := antlr.NewATNDeserializer(nil) + staticData.atn = deserializer.Deserialize(staticData.serializedATN) + atn := staticData.atn + staticData.decisionToDFA = make([]*antlr.DFA, len(atn.DecisionToState)) + decisionToDFA := staticData.decisionToDFA + for index, state := range atn.DecisionToState { + decisionToDFA[index] = antlr.NewDFA(state, index) + } +} + +// MatchLexerInit initializes any static state used to implement MatchLexer. By default the +// static state used to implement the lexer is lazily initialized during the first call to +// NewMatchLexer(). You can call this function if you wish to initialize the static state ahead +// of time. +func MatchLexerInit() { + staticData := &MatchLexerLexerStaticData + staticData.once.Do(matchlexerLexerInit) +} + +// NewMatchLexer produces a new lexer instance for the optional input antlr.CharStream. +func NewMatchLexer(input antlr.CharStream) *MatchLexer { + MatchLexerInit() + l := new(MatchLexer) + l.BaseLexer = antlr.NewBaseLexer(input) + staticData := &MatchLexerLexerStaticData + l.Interpreter = antlr.NewLexerATNSimulator(l, staticData.atn, staticData.decisionToDFA, staticData.PredictionContextCache) + l.channelNames = staticData.ChannelNames + l.modeNames = staticData.ModeNames + l.RuleNames = staticData.RuleNames + l.LiteralNames = staticData.LiteralNames + l.SymbolicNames = staticData.SymbolicNames + l.GrammarFileName = "Match.g4" + // TODO: l.EOF = antlr.TokenEOF + + return l +} + +// MatchLexer tokens. +const ( + MatchLexerUSER = 1 + MatchLexerGROUP = 2 + MatchLexerHOST = 3 + MatchLexerLOCALADDRESS = 4 + MatchLexerLOCALPORT = 5 + MatchLexerRDOMAIN = 6 + MatchLexerADDRESS = 7 + MatchLexerCOMMA = 8 + MatchLexerSTRING = 9 + MatchLexerWHITESPACE = 10 +) diff --git a/handlers/sshd_config/fields/match-parser/parser/match_listener.go b/handlers/sshd_config/fields/match-parser/parser/match_listener.go new file mode 100644 index 0000000..8db9553 --- /dev/null +++ b/handlers/sshd_config/fields/match-parser/parser/match_listener.go @@ -0,0 +1,40 @@ +// Code generated from Match.g4 by ANTLR 4.13.0. DO NOT EDIT. + +package parser // Match + +import "github.com/antlr4-go/antlr/v4" + +// MatchListener is a complete listener for a parse tree produced by MatchParser. +type MatchListener interface { + antlr.ParseTreeListener + + // EnterRoot is called when entering the root production. + EnterRoot(c *RootContext) + + // EnterMatchEntry is called when entering the matchEntry production. + EnterMatchEntry(c *MatchEntryContext) + + // EnterCriteria is called when entering the criteria production. + EnterCriteria(c *CriteriaContext) + + // EnterValues is called when entering the values production. + EnterValues(c *ValuesContext) + + // EnterValue is called when entering the value production. + EnterValue(c *ValueContext) + + // ExitRoot is called when exiting the root production. + ExitRoot(c *RootContext) + + // ExitMatchEntry is called when exiting the matchEntry production. + ExitMatchEntry(c *MatchEntryContext) + + // ExitCriteria is called when exiting the criteria production. + ExitCriteria(c *CriteriaContext) + + // ExitValues is called when exiting the values production. + ExitValues(c *ValuesContext) + + // ExitValue is called when exiting the value production. + ExitValue(c *ValueContext) +} diff --git a/handlers/sshd_config/fields/match-parser/parser/match_parser.go b/handlers/sshd_config/fields/match-parser/parser/match_parser.go new file mode 100644 index 0000000..79a4ea4 --- /dev/null +++ b/handlers/sshd_config/fields/match-parser/parser/match_parser.go @@ -0,0 +1,887 @@ +// Code generated from Match.g4 by ANTLR 4.13.0. DO NOT EDIT. + +package parser // Match + +import ( + "fmt" + "strconv" + "sync" + + "github.com/antlr4-go/antlr/v4" +) + +// Suppress unused import errors +var _ = fmt.Printf +var _ = strconv.Itoa +var _ = sync.Once{} + +type MatchParser struct { + *antlr.BaseParser +} + +var MatchParserStaticData struct { + once sync.Once + serializedATN []int32 + LiteralNames []string + SymbolicNames []string + RuleNames []string + PredictionContextCache *antlr.PredictionContextCache + atn *antlr.ATN + decisionToDFA []*antlr.DFA +} + +func matchParserInit() { + staticData := &MatchParserStaticData + staticData.LiteralNames = []string{ + "", "", "", "", "", "", "", "", "','", + } + staticData.SymbolicNames = []string{ + "", "USER", "GROUP", "HOST", "LOCALADDRESS", "LOCALPORT", "RDOMAIN", + "ADDRESS", "COMMA", "STRING", "WHITESPACE", + } + staticData.RuleNames = []string{ + "root", "matchEntry", "criteria", "values", "value", + } + staticData.PredictionContextCache = antlr.NewPredictionContextCache() + staticData.serializedATN = []int32{ + 4, 1, 10, 46, 2, 0, 7, 0, 2, 1, 7, 1, 2, 2, 7, 2, 2, 3, 7, 3, 2, 4, 7, + 4, 1, 0, 3, 0, 12, 8, 0, 1, 0, 1, 0, 5, 0, 16, 8, 0, 10, 0, 12, 0, 19, + 9, 0, 1, 0, 1, 0, 1, 1, 1, 1, 3, 1, 25, 8, 1, 1, 1, 3, 1, 28, 8, 1, 1, + 2, 1, 2, 1, 3, 3, 3, 33, 8, 3, 1, 3, 1, 3, 3, 3, 37, 8, 3, 5, 3, 39, 8, + 3, 10, 3, 12, 3, 42, 9, 3, 1, 4, 1, 4, 1, 4, 0, 0, 5, 0, 2, 4, 6, 8, 0, + 1, 1, 0, 1, 7, 47, 0, 11, 1, 0, 0, 0, 2, 22, 1, 0, 0, 0, 4, 29, 1, 0, 0, + 0, 6, 32, 1, 0, 0, 0, 8, 43, 1, 0, 0, 0, 10, 12, 3, 2, 1, 0, 11, 10, 1, + 0, 0, 0, 11, 12, 1, 0, 0, 0, 12, 17, 1, 0, 0, 0, 13, 14, 5, 10, 0, 0, 14, + 16, 3, 2, 1, 0, 15, 13, 1, 0, 0, 0, 16, 19, 1, 0, 0, 0, 17, 15, 1, 0, 0, + 0, 17, 18, 1, 0, 0, 0, 18, 20, 1, 0, 0, 0, 19, 17, 1, 0, 0, 0, 20, 21, + 5, 0, 0, 1, 21, 1, 1, 0, 0, 0, 22, 24, 3, 4, 2, 0, 23, 25, 5, 10, 0, 0, + 24, 23, 1, 0, 0, 0, 24, 25, 1, 0, 0, 0, 25, 27, 1, 0, 0, 0, 26, 28, 3, + 6, 3, 0, 27, 26, 1, 0, 0, 0, 27, 28, 1, 0, 0, 0, 28, 3, 1, 0, 0, 0, 29, + 30, 7, 0, 0, 0, 30, 5, 1, 0, 0, 0, 31, 33, 3, 8, 4, 0, 32, 31, 1, 0, 0, + 0, 32, 33, 1, 0, 0, 0, 33, 40, 1, 0, 0, 0, 34, 36, 5, 8, 0, 0, 35, 37, + 3, 8, 4, 0, 36, 35, 1, 0, 0, 0, 36, 37, 1, 0, 0, 0, 37, 39, 1, 0, 0, 0, + 38, 34, 1, 0, 0, 0, 39, 42, 1, 0, 0, 0, 40, 38, 1, 0, 0, 0, 40, 41, 1, + 0, 0, 0, 41, 7, 1, 0, 0, 0, 42, 40, 1, 0, 0, 0, 43, 44, 5, 9, 0, 0, 44, + 9, 1, 0, 0, 0, 7, 11, 17, 24, 27, 32, 36, 40, + } + deserializer := antlr.NewATNDeserializer(nil) + staticData.atn = deserializer.Deserialize(staticData.serializedATN) + atn := staticData.atn + staticData.decisionToDFA = make([]*antlr.DFA, len(atn.DecisionToState)) + decisionToDFA := staticData.decisionToDFA + for index, state := range atn.DecisionToState { + decisionToDFA[index] = antlr.NewDFA(state, index) + } +} + +// MatchParserInit initializes any static state used to implement MatchParser. By default the +// static state used to implement the parser is lazily initialized during the first call to +// NewMatchParser(). You can call this function if you wish to initialize the static state ahead +// of time. +func MatchParserInit() { + staticData := &MatchParserStaticData + staticData.once.Do(matchParserInit) +} + +// NewMatchParser produces a new parser instance for the optional input antlr.TokenStream. +func NewMatchParser(input antlr.TokenStream) *MatchParser { + MatchParserInit() + this := new(MatchParser) + this.BaseParser = antlr.NewBaseParser(input) + staticData := &MatchParserStaticData + this.Interpreter = antlr.NewParserATNSimulator(this, staticData.atn, staticData.decisionToDFA, staticData.PredictionContextCache) + this.RuleNames = staticData.RuleNames + this.LiteralNames = staticData.LiteralNames + this.SymbolicNames = staticData.SymbolicNames + this.GrammarFileName = "Match.g4" + + return this +} + +// MatchParser tokens. +const ( + MatchParserEOF = antlr.TokenEOF + MatchParserUSER = 1 + MatchParserGROUP = 2 + MatchParserHOST = 3 + MatchParserLOCALADDRESS = 4 + MatchParserLOCALPORT = 5 + MatchParserRDOMAIN = 6 + MatchParserADDRESS = 7 + MatchParserCOMMA = 8 + MatchParserSTRING = 9 + MatchParserWHITESPACE = 10 +) + +// MatchParser rules. +const ( + MatchParserRULE_root = 0 + MatchParserRULE_matchEntry = 1 + MatchParserRULE_criteria = 2 + MatchParserRULE_values = 3 + MatchParserRULE_value = 4 +) + +// IRootContext is an interface to support dynamic dispatch. +type IRootContext interface { + antlr.ParserRuleContext + + // GetParser returns the parser. + GetParser() antlr.Parser + + // Getter signatures + EOF() antlr.TerminalNode + AllMatchEntry() []IMatchEntryContext + MatchEntry(i int) IMatchEntryContext + AllWHITESPACE() []antlr.TerminalNode + WHITESPACE(i int) antlr.TerminalNode + + // IsRootContext differentiates from other interfaces. + IsRootContext() +} + +type RootContext struct { + antlr.BaseParserRuleContext + parser antlr.Parser +} + +func NewEmptyRootContext() *RootContext { + var p = new(RootContext) + antlr.InitBaseParserRuleContext(&p.BaseParserRuleContext, nil, -1) + p.RuleIndex = MatchParserRULE_root + return p +} + +func InitEmptyRootContext(p *RootContext) { + antlr.InitBaseParserRuleContext(&p.BaseParserRuleContext, nil, -1) + p.RuleIndex = MatchParserRULE_root +} + +func (*RootContext) IsRootContext() {} + +func NewRootContext(parser antlr.Parser, parent antlr.ParserRuleContext, invokingState int) *RootContext { + var p = new(RootContext) + + antlr.InitBaseParserRuleContext(&p.BaseParserRuleContext, parent, invokingState) + + p.parser = parser + p.RuleIndex = MatchParserRULE_root + + return p +} + +func (s *RootContext) GetParser() antlr.Parser { return s.parser } + +func (s *RootContext) EOF() antlr.TerminalNode { + return s.GetToken(MatchParserEOF, 0) +} + +func (s *RootContext) AllMatchEntry() []IMatchEntryContext { + children := s.GetChildren() + len := 0 + for _, ctx := range children { + if _, ok := ctx.(IMatchEntryContext); ok { + len++ + } + } + + tst := make([]IMatchEntryContext, len) + i := 0 + for _, ctx := range children { + if t, ok := ctx.(IMatchEntryContext); ok { + tst[i] = t.(IMatchEntryContext) + i++ + } + } + + return tst +} + +func (s *RootContext) MatchEntry(i int) IMatchEntryContext { + var t antlr.RuleContext + j := 0 + for _, ctx := range s.GetChildren() { + if _, ok := ctx.(IMatchEntryContext); ok { + if j == i { + t = ctx.(antlr.RuleContext) + break + } + j++ + } + } + + if t == nil { + return nil + } + + return t.(IMatchEntryContext) +} + +func (s *RootContext) AllWHITESPACE() []antlr.TerminalNode { + return s.GetTokens(MatchParserWHITESPACE) +} + +func (s *RootContext) WHITESPACE(i int) antlr.TerminalNode { + return s.GetToken(MatchParserWHITESPACE, i) +} + +func (s *RootContext) GetRuleContext() antlr.RuleContext { + return s +} + +func (s *RootContext) ToStringTree(ruleNames []string, recog antlr.Recognizer) string { + return antlr.TreesStringTree(s, ruleNames, recog) +} + +func (s *RootContext) EnterRule(listener antlr.ParseTreeListener) { + if listenerT, ok := listener.(MatchListener); ok { + listenerT.EnterRoot(s) + } +} + +func (s *RootContext) ExitRule(listener antlr.ParseTreeListener) { + if listenerT, ok := listener.(MatchListener); ok { + listenerT.ExitRoot(s) + } +} + +func (p *MatchParser) Root() (localctx IRootContext) { + localctx = NewRootContext(p, p.GetParserRuleContext(), p.GetState()) + p.EnterRule(localctx, 0, MatchParserRULE_root) + var _la int + + p.EnterOuterAlt(localctx, 1) + p.SetState(11) + p.GetErrorHandler().Sync(p) + if p.HasError() { + goto errorExit + } + _la = p.GetTokenStream().LA(1) + + if (int64(_la) & ^0x3f) == 0 && ((int64(1)<<_la)&254) != 0 { + { + p.SetState(10) + p.MatchEntry() + } + + } + p.SetState(17) + p.GetErrorHandler().Sync(p) + if p.HasError() { + goto errorExit + } + _la = p.GetTokenStream().LA(1) + + for _la == MatchParserWHITESPACE { + { + p.SetState(13) + p.Match(MatchParserWHITESPACE) + if p.HasError() { + // Recognition error - abort rule + goto errorExit + } + } + { + p.SetState(14) + p.MatchEntry() + } + + p.SetState(19) + p.GetErrorHandler().Sync(p) + if p.HasError() { + goto errorExit + } + _la = p.GetTokenStream().LA(1) + } + { + p.SetState(20) + p.Match(MatchParserEOF) + if p.HasError() { + // Recognition error - abort rule + goto errorExit + } + } + +errorExit: + if p.HasError() { + v := p.GetError() + localctx.SetException(v) + p.GetErrorHandler().ReportError(p, v) + p.GetErrorHandler().Recover(p, v) + p.SetError(nil) + } + p.ExitRule() + return localctx + goto errorExit // Trick to prevent compiler error if the label is not used +} + +// IMatchEntryContext is an interface to support dynamic dispatch. +type IMatchEntryContext interface { + antlr.ParserRuleContext + + // GetParser returns the parser. + GetParser() antlr.Parser + + // Getter signatures + Criteria() ICriteriaContext + WHITESPACE() antlr.TerminalNode + Values() IValuesContext + + // IsMatchEntryContext differentiates from other interfaces. + IsMatchEntryContext() +} + +type MatchEntryContext struct { + antlr.BaseParserRuleContext + parser antlr.Parser +} + +func NewEmptyMatchEntryContext() *MatchEntryContext { + var p = new(MatchEntryContext) + antlr.InitBaseParserRuleContext(&p.BaseParserRuleContext, nil, -1) + p.RuleIndex = MatchParserRULE_matchEntry + return p +} + +func InitEmptyMatchEntryContext(p *MatchEntryContext) { + antlr.InitBaseParserRuleContext(&p.BaseParserRuleContext, nil, -1) + p.RuleIndex = MatchParserRULE_matchEntry +} + +func (*MatchEntryContext) IsMatchEntryContext() {} + +func NewMatchEntryContext(parser antlr.Parser, parent antlr.ParserRuleContext, invokingState int) *MatchEntryContext { + var p = new(MatchEntryContext) + + antlr.InitBaseParserRuleContext(&p.BaseParserRuleContext, parent, invokingState) + + p.parser = parser + p.RuleIndex = MatchParserRULE_matchEntry + + return p +} + +func (s *MatchEntryContext) GetParser() antlr.Parser { return s.parser } + +func (s *MatchEntryContext) Criteria() ICriteriaContext { + var t antlr.RuleContext + for _, ctx := range s.GetChildren() { + if _, ok := ctx.(ICriteriaContext); ok { + t = ctx.(antlr.RuleContext) + break + } + } + + if t == nil { + return nil + } + + return t.(ICriteriaContext) +} + +func (s *MatchEntryContext) WHITESPACE() antlr.TerminalNode { + return s.GetToken(MatchParserWHITESPACE, 0) +} + +func (s *MatchEntryContext) Values() IValuesContext { + var t antlr.RuleContext + for _, ctx := range s.GetChildren() { + if _, ok := ctx.(IValuesContext); ok { + t = ctx.(antlr.RuleContext) + break + } + } + + if t == nil { + return nil + } + + return t.(IValuesContext) +} + +func (s *MatchEntryContext) GetRuleContext() antlr.RuleContext { + return s +} + +func (s *MatchEntryContext) ToStringTree(ruleNames []string, recog antlr.Recognizer) string { + return antlr.TreesStringTree(s, ruleNames, recog) +} + +func (s *MatchEntryContext) EnterRule(listener antlr.ParseTreeListener) { + if listenerT, ok := listener.(MatchListener); ok { + listenerT.EnterMatchEntry(s) + } +} + +func (s *MatchEntryContext) ExitRule(listener antlr.ParseTreeListener) { + if listenerT, ok := listener.(MatchListener); ok { + listenerT.ExitMatchEntry(s) + } +} + +func (p *MatchParser) MatchEntry() (localctx IMatchEntryContext) { + localctx = NewMatchEntryContext(p, p.GetParserRuleContext(), p.GetState()) + p.EnterRule(localctx, 2, MatchParserRULE_matchEntry) + p.EnterOuterAlt(localctx, 1) + { + p.SetState(22) + p.Criteria() + } + p.SetState(24) + p.GetErrorHandler().Sync(p) + + if p.GetInterpreter().AdaptivePredict(p.BaseParser, p.GetTokenStream(), 2, p.GetParserRuleContext()) == 1 { + { + p.SetState(23) + p.Match(MatchParserWHITESPACE) + if p.HasError() { + // Recognition error - abort rule + goto errorExit + } + } + + } else if p.HasError() { // JIM + goto errorExit + } + p.SetState(27) + p.GetErrorHandler().Sync(p) + + if p.GetInterpreter().AdaptivePredict(p.BaseParser, p.GetTokenStream(), 3, p.GetParserRuleContext()) == 1 { + { + p.SetState(26) + p.Values() + } + + } else if p.HasError() { // JIM + goto errorExit + } + +errorExit: + if p.HasError() { + v := p.GetError() + localctx.SetException(v) + p.GetErrorHandler().ReportError(p, v) + p.GetErrorHandler().Recover(p, v) + p.SetError(nil) + } + p.ExitRule() + return localctx + goto errorExit // Trick to prevent compiler error if the label is not used +} + +// ICriteriaContext is an interface to support dynamic dispatch. +type ICriteriaContext interface { + antlr.ParserRuleContext + + // GetParser returns the parser. + GetParser() antlr.Parser + + // Getter signatures + USER() antlr.TerminalNode + GROUP() antlr.TerminalNode + HOST() antlr.TerminalNode + LOCALADDRESS() antlr.TerminalNode + LOCALPORT() antlr.TerminalNode + RDOMAIN() antlr.TerminalNode + ADDRESS() antlr.TerminalNode + + // IsCriteriaContext differentiates from other interfaces. + IsCriteriaContext() +} + +type CriteriaContext struct { + antlr.BaseParserRuleContext + parser antlr.Parser +} + +func NewEmptyCriteriaContext() *CriteriaContext { + var p = new(CriteriaContext) + antlr.InitBaseParserRuleContext(&p.BaseParserRuleContext, nil, -1) + p.RuleIndex = MatchParserRULE_criteria + return p +} + +func InitEmptyCriteriaContext(p *CriteriaContext) { + antlr.InitBaseParserRuleContext(&p.BaseParserRuleContext, nil, -1) + p.RuleIndex = MatchParserRULE_criteria +} + +func (*CriteriaContext) IsCriteriaContext() {} + +func NewCriteriaContext(parser antlr.Parser, parent antlr.ParserRuleContext, invokingState int) *CriteriaContext { + var p = new(CriteriaContext) + + antlr.InitBaseParserRuleContext(&p.BaseParserRuleContext, parent, invokingState) + + p.parser = parser + p.RuleIndex = MatchParserRULE_criteria + + return p +} + +func (s *CriteriaContext) GetParser() antlr.Parser { return s.parser } + +func (s *CriteriaContext) USER() antlr.TerminalNode { + return s.GetToken(MatchParserUSER, 0) +} + +func (s *CriteriaContext) GROUP() antlr.TerminalNode { + return s.GetToken(MatchParserGROUP, 0) +} + +func (s *CriteriaContext) HOST() antlr.TerminalNode { + return s.GetToken(MatchParserHOST, 0) +} + +func (s *CriteriaContext) LOCALADDRESS() antlr.TerminalNode { + return s.GetToken(MatchParserLOCALADDRESS, 0) +} + +func (s *CriteriaContext) LOCALPORT() antlr.TerminalNode { + return s.GetToken(MatchParserLOCALPORT, 0) +} + +func (s *CriteriaContext) RDOMAIN() antlr.TerminalNode { + return s.GetToken(MatchParserRDOMAIN, 0) +} + +func (s *CriteriaContext) ADDRESS() antlr.TerminalNode { + return s.GetToken(MatchParserADDRESS, 0) +} + +func (s *CriteriaContext) GetRuleContext() antlr.RuleContext { + return s +} + +func (s *CriteriaContext) ToStringTree(ruleNames []string, recog antlr.Recognizer) string { + return antlr.TreesStringTree(s, ruleNames, recog) +} + +func (s *CriteriaContext) EnterRule(listener antlr.ParseTreeListener) { + if listenerT, ok := listener.(MatchListener); ok { + listenerT.EnterCriteria(s) + } +} + +func (s *CriteriaContext) ExitRule(listener antlr.ParseTreeListener) { + if listenerT, ok := listener.(MatchListener); ok { + listenerT.ExitCriteria(s) + } +} + +func (p *MatchParser) Criteria() (localctx ICriteriaContext) { + localctx = NewCriteriaContext(p, p.GetParserRuleContext(), p.GetState()) + p.EnterRule(localctx, 4, MatchParserRULE_criteria) + var _la int + + p.EnterOuterAlt(localctx, 1) + { + p.SetState(29) + _la = p.GetTokenStream().LA(1) + + if !((int64(_la) & ^0x3f) == 0 && ((int64(1)<<_la)&254) != 0) { + p.GetErrorHandler().RecoverInline(p) + } else { + p.GetErrorHandler().ReportMatch(p) + p.Consume() + } + } + +errorExit: + if p.HasError() { + v := p.GetError() + localctx.SetException(v) + p.GetErrorHandler().ReportError(p, v) + p.GetErrorHandler().Recover(p, v) + p.SetError(nil) + } + p.ExitRule() + return localctx + goto errorExit // Trick to prevent compiler error if the label is not used +} + +// IValuesContext is an interface to support dynamic dispatch. +type IValuesContext interface { + antlr.ParserRuleContext + + // GetParser returns the parser. + GetParser() antlr.Parser + + // Getter signatures + AllValue() []IValueContext + Value(i int) IValueContext + AllCOMMA() []antlr.TerminalNode + COMMA(i int) antlr.TerminalNode + + // IsValuesContext differentiates from other interfaces. + IsValuesContext() +} + +type ValuesContext struct { + antlr.BaseParserRuleContext + parser antlr.Parser +} + +func NewEmptyValuesContext() *ValuesContext { + var p = new(ValuesContext) + antlr.InitBaseParserRuleContext(&p.BaseParserRuleContext, nil, -1) + p.RuleIndex = MatchParserRULE_values + return p +} + +func InitEmptyValuesContext(p *ValuesContext) { + antlr.InitBaseParserRuleContext(&p.BaseParserRuleContext, nil, -1) + p.RuleIndex = MatchParserRULE_values +} + +func (*ValuesContext) IsValuesContext() {} + +func NewValuesContext(parser antlr.Parser, parent antlr.ParserRuleContext, invokingState int) *ValuesContext { + var p = new(ValuesContext) + + antlr.InitBaseParserRuleContext(&p.BaseParserRuleContext, parent, invokingState) + + p.parser = parser + p.RuleIndex = MatchParserRULE_values + + return p +} + +func (s *ValuesContext) GetParser() antlr.Parser { return s.parser } + +func (s *ValuesContext) AllValue() []IValueContext { + children := s.GetChildren() + len := 0 + for _, ctx := range children { + if _, ok := ctx.(IValueContext); ok { + len++ + } + } + + tst := make([]IValueContext, len) + i := 0 + for _, ctx := range children { + if t, ok := ctx.(IValueContext); ok { + tst[i] = t.(IValueContext) + i++ + } + } + + return tst +} + +func (s *ValuesContext) Value(i int) IValueContext { + var t antlr.RuleContext + j := 0 + for _, ctx := range s.GetChildren() { + if _, ok := ctx.(IValueContext); ok { + if j == i { + t = ctx.(antlr.RuleContext) + break + } + j++ + } + } + + if t == nil { + return nil + } + + return t.(IValueContext) +} + +func (s *ValuesContext) AllCOMMA() []antlr.TerminalNode { + return s.GetTokens(MatchParserCOMMA) +} + +func (s *ValuesContext) COMMA(i int) antlr.TerminalNode { + return s.GetToken(MatchParserCOMMA, i) +} + +func (s *ValuesContext) GetRuleContext() antlr.RuleContext { + return s +} + +func (s *ValuesContext) ToStringTree(ruleNames []string, recog antlr.Recognizer) string { + return antlr.TreesStringTree(s, ruleNames, recog) +} + +func (s *ValuesContext) EnterRule(listener antlr.ParseTreeListener) { + if listenerT, ok := listener.(MatchListener); ok { + listenerT.EnterValues(s) + } +} + +func (s *ValuesContext) ExitRule(listener antlr.ParseTreeListener) { + if listenerT, ok := listener.(MatchListener); ok { + listenerT.ExitValues(s) + } +} + +func (p *MatchParser) Values() (localctx IValuesContext) { + localctx = NewValuesContext(p, p.GetParserRuleContext(), p.GetState()) + p.EnterRule(localctx, 6, MatchParserRULE_values) + var _la int + + p.EnterOuterAlt(localctx, 1) + p.SetState(32) + p.GetErrorHandler().Sync(p) + if p.HasError() { + goto errorExit + } + _la = p.GetTokenStream().LA(1) + + if _la == MatchParserSTRING { + { + p.SetState(31) + p.Value() + } + + } + p.SetState(40) + p.GetErrorHandler().Sync(p) + if p.HasError() { + goto errorExit + } + _la = p.GetTokenStream().LA(1) + + for _la == MatchParserCOMMA { + { + p.SetState(34) + p.Match(MatchParserCOMMA) + if p.HasError() { + // Recognition error - abort rule + goto errorExit + } + } + p.SetState(36) + p.GetErrorHandler().Sync(p) + if p.HasError() { + goto errorExit + } + _la = p.GetTokenStream().LA(1) + + if _la == MatchParserSTRING { + { + p.SetState(35) + p.Value() + } + + } + + p.SetState(42) + p.GetErrorHandler().Sync(p) + if p.HasError() { + goto errorExit + } + _la = p.GetTokenStream().LA(1) + } + +errorExit: + if p.HasError() { + v := p.GetError() + localctx.SetException(v) + p.GetErrorHandler().ReportError(p, v) + p.GetErrorHandler().Recover(p, v) + p.SetError(nil) + } + p.ExitRule() + return localctx + goto errorExit // Trick to prevent compiler error if the label is not used +} + +// IValueContext is an interface to support dynamic dispatch. +type IValueContext interface { + antlr.ParserRuleContext + + // GetParser returns the parser. + GetParser() antlr.Parser + + // Getter signatures + STRING() antlr.TerminalNode + + // IsValueContext differentiates from other interfaces. + IsValueContext() +} + +type ValueContext struct { + antlr.BaseParserRuleContext + parser antlr.Parser +} + +func NewEmptyValueContext() *ValueContext { + var p = new(ValueContext) + antlr.InitBaseParserRuleContext(&p.BaseParserRuleContext, nil, -1) + p.RuleIndex = MatchParserRULE_value + return p +} + +func InitEmptyValueContext(p *ValueContext) { + antlr.InitBaseParserRuleContext(&p.BaseParserRuleContext, nil, -1) + p.RuleIndex = MatchParserRULE_value +} + +func (*ValueContext) IsValueContext() {} + +func NewValueContext(parser antlr.Parser, parent antlr.ParserRuleContext, invokingState int) *ValueContext { + var p = new(ValueContext) + + antlr.InitBaseParserRuleContext(&p.BaseParserRuleContext, parent, invokingState) + + p.parser = parser + p.RuleIndex = MatchParserRULE_value + + return p +} + +func (s *ValueContext) GetParser() antlr.Parser { return s.parser } + +func (s *ValueContext) STRING() antlr.TerminalNode { + return s.GetToken(MatchParserSTRING, 0) +} + +func (s *ValueContext) GetRuleContext() antlr.RuleContext { + return s +} + +func (s *ValueContext) ToStringTree(ruleNames []string, recog antlr.Recognizer) string { + return antlr.TreesStringTree(s, ruleNames, recog) +} + +func (s *ValueContext) EnterRule(listener antlr.ParseTreeListener) { + if listenerT, ok := listener.(MatchListener); ok { + listenerT.EnterValue(s) + } +} + +func (s *ValueContext) ExitRule(listener antlr.ParseTreeListener) { + if listenerT, ok := listener.(MatchListener); ok { + listenerT.ExitValue(s) + } +} + +func (p *MatchParser) Value() (localctx IValueContext) { + localctx = NewValueContext(p, p.GetParserRuleContext(), p.GetState()) + p.EnterRule(localctx, 8, MatchParserRULE_value) + p.EnterOuterAlt(localctx, 1) + { + p.SetState(43) + p.Match(MatchParserSTRING) + if p.HasError() { + // Recognition error - abort rule + goto errorExit + } + } + +errorExit: + if p.HasError() { + v := p.GetError() + localctx.SetException(v) + p.GetErrorHandler().ReportError(p, v) + p.GetErrorHandler().Recover(p, v) + p.SetError(nil) + } + p.ExitRule() + return localctx + goto errorExit // Trick to prevent compiler error if the label is not used +} diff --git a/handlers/sshd_config/fields/match-parser/parser_test.go b/handlers/sshd_config/fields/match-parser/parser_test.go new file mode 100644 index 0000000..df9395c --- /dev/null +++ b/handlers/sshd_config/fields/match-parser/parser_test.go @@ -0,0 +1,79 @@ +package match_parser + +import ( + "testing" +) + +func TestComplexExample( + t *testing.T, +) { + input := "User root,admin,alice Address *,!192.168.0.1" + + match := NewMatch() + errors := match.Parse(input, 32) + + if len(errors) > 0 { + t.Fatalf("Expected no errors, but got %v", errors) + } + + if !(len(match.Entries) == 2) { + t.Fatalf("Expected 2 entries, but got %v", len(match.Entries)) + } + + if !(match.Entries[0].Criteria == MatchCriteriaTypeUser) { + t.Fatalf("Expected User, but got %v", match.Entries[0]) + } + + if !(match.Entries[0].Values[0].Value == "root") { + t.Fatalf("Expected root, but got %v", match.Entries[0].Values[0]) + } + + if !(match.Entries[0].Values[1].Value == "admin") { + t.Fatalf("Expected admin, but got %v", match.Entries[0].Values[1]) + } + + if !(match.Entries[0].Values[2].Value == "alice") { + t.Fatalf("Expected alice, but got %v", match.Entries[0].Values[2]) + } + + if !(match.Entries[1].Criteria == MatchCriteriaTypeAddress) { + t.Fatalf("Expected Address, but got %v", match.Entries[1]) + } + + if !(match.Entries[1].Values[0].Value == "*") { + t.Fatalf("Expected *, but got %v", match.Entries[1].Values[0]) + } + + if !(match.Entries[1].Values[1].Value == "!192.168.0.1") { + t.Fatalf("Expected !192.168.0.1, but got %v", match.Entries[1].Values[1]) + } +} + +func TestSecondComplexExample( + t *testing.T, +) { + input := "Address 172.22.100.0/24,172.22.5.0/24,127.0.0.1" + + match := NewMatch() + errors := match.Parse(input, 0) + + if len(errors) > 0 { + t.Fatalf("Expected no errors, but got %v", errors) + } + + if !(len(match.Entries) == 1) { + t.Fatalf("Expected 1 entries, but got %v", len(match.Entries)) + } + + if !(match.Entries[0].Criteria == MatchCriteriaTypeAddress) { + t.Fatalf("Expected Address, but got %v", match.Entries[0]) + } + + if !(len(match.Entries[0].Values) == 3) { + t.Fatalf("Expected 3 values, but got %v", len(match.Entries[0].Values)) + } + + if !(match.Entries[0].Values[0].Value == "172.22.100.0/24") { + t.Fatalf("Expected 172.22.100.0/24, but got %v", match.Entries[0].Values[0]) + } +}