From 5aaa0d92837520a05af14b32cea04273accf1cb9 Mon Sep 17 00:00:00 2001 From: Graham Gilbert Date: Mon, 24 Aug 2020 14:28:15 -0700 Subject: [PATCH] File lines table --- Makefile | 14 +---- README.md | 1 + main.go | 2 + tables/fileline/file_line.go | 107 +++++++++++++++++++++++++++++++++++ 4 files changed, 112 insertions(+), 12 deletions(-) create mode 100644 tables/fileline/file_line.go diff --git a/Makefile b/Makefile index 459ca7e..3834e19 100644 --- a/Makefile +++ b/Makefile @@ -5,18 +5,7 @@ SHELL = /bin/sh APP_NAME = macadmins_extension PKGDIR_TMP = ${TMPDIR}golang -OSQUERYI = sudo osqueryi --extension build/linux/macadmins_extension.ext --allow_unsafe --extensions_autoload=/ --config-path=/ --extensions_timeout=60 - -ifneq ($(OS), Windows_NT) - CURRENT_PLATFORM = linux - ifeq ($(shell uname), Darwin) - SHELL := /bin/sh - CURRENT_PLATFORM = darwin - OSQUERYI = sudo osqueryi --extension build/Darwin/macadmins_extension.ext --allow_unsafe --extensions_autoload=/ --config-path=/ --extensions_timeout=60 - endif -else - CURRENT_PLATFORM = windows -endif +OSQUERYI = sudo osqueryi --extension=build/Darwin/macadmins_extension.ext --allow_unsafe --extensions_autoload=/ --config-path=/ --extensions_timeout=60 all: build @@ -48,6 +37,7 @@ build: .pre-build osqueryi: build + sleep 2 OSQUERYI zip: build diff --git a/README.md b/README.md index 41177aa..8bd1635 100644 --- a/README.md +++ b/README.md @@ -16,6 +16,7 @@ For production deployment, you should refer to the [osquery documentation](https | Table | Description | Platforms | Notes | | ------------------------ | --------------------------------------------------------------------------------------------- | ----------------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | +| `line_lines` | Read an arbitrary file | Linux / macOS / Windows | Use the constraint `path` and `last` to specify the file to read lines from | | `filevault_users` | Information on the users able to unlock the current boot volume when encrypted with Filevault | macOS | | | `google_chrome_profiles` | Profiles configured in Goolge Chrome. | Linux / macOS / Windows | | | `macos_profiles` | High level information on installed profiles enrollment | macOS | diff --git a/main.go b/main.go index 8a2f0fe..2d31854 100644 --- a/main.go +++ b/main.go @@ -9,6 +9,7 @@ import ( osquery "github.com/kolide/osquery-go" "github.com/kolide/osquery-go/plugin/table" "github.com/macadmins/osquery-extension/tables/chromeuserprofiles" + "github.com/macadmins/osquery-extension/tables/fileline" "github.com/macadmins/osquery-extension/tables/filevaultusers" macosprofiles "github.com/macadmins/osquery-extension/tables/macos_profiles" "github.com/macadmins/osquery-extension/tables/mdm" @@ -46,6 +47,7 @@ func main() { table.NewPlugin("puppet_logs", puppet.PuppetLogsColumns(), puppet.PuppetLogsGenerate), table.NewPlugin("puppet_state", puppet.PuppetStateColumns(), puppet.PuppetStateGenerate), table.NewPlugin("google_chrome_profiles", chromeuserprofiles.GoogleChromeProfilesColumns(), chromeuserprofiles.GoogleChromeProfilesGenerate), + table.NewPlugin("file_lines", fileline.FileLineColumns(), fileline.FileLineGenerate), } // Platform specific tables diff --git a/tables/fileline/file_line.go b/tables/fileline/file_line.go new file mode 100644 index 0000000..ee2c22d --- /dev/null +++ b/tables/fileline/file_line.go @@ -0,0 +1,107 @@ +package fileline + +import ( + "bufio" + "context" + "errors" + "fmt" + "os" + "path/filepath" + "strings" + + "github.com/kolide/osquery-go/plugin/table" +) + +type FileLine struct { + Line string + Path string +} + +func FileLineColumns() []table.ColumnDefinition { + return []table.ColumnDefinition{ + table.TextColumn("line"), + table.TextColumn("path"), + } +} + +func FileLineGenerate(ctx context.Context, queryContext table.QueryContext) ([]map[string]string, error) { + + path := "" + + if constraintList, present := queryContext.Constraints["path"]; present { + // 'path' is in the where clause + for _, constraint := range constraintList.Constraints { + if constraint.Operator == table.OperatorEquals { + path = constraint.Expression + } + } + } + + output, err := processFile(path) + if err != nil { + return nil, err + } + + return output, nil +} + +func processFile(path string) ([]map[string]string, error) { + + var output []map[string]string + + // Replace % for * for glob + replacedPath := strings.ReplaceAll(path, "%", "*") + + files, err := filepath.Glob(replacedPath) + if err != nil { + return nil, err + } + + for _, file := range files { + // get slice of lines + lines, _ := readLines(file) + + for _, line := range lines { + output = append(output, map[string]string{ + "line": line, + "path": file, + }) + } + } + + return output, nil + +} + +func readLines(path string) ([]string, error) { + var output []string + fmt.Println(path) + if !fileExists(path) { + err := errors.New("File does not exist") + return nil, err + } + file, err := os.Open(path) + if err != nil { + return nil, err + } + defer file.Close() + + scanner := bufio.NewScanner(file) + for scanner.Scan() { + output = append(output, scanner.Text()) + } + + if err := scanner.Err(); err != nil { + return nil, err + } + + return output, nil +} + +func fileExists(filename string) bool { + info, err := os.Stat(filename) + if os.IsNotExist(err) { + return false + } + return !info.IsDir() +}