فهرست منبع

Tighten windows sqlite database permissions (#1769)

blotus 2 سال پیش
والد
کامیت
bfbe180101

+ 1 - 0
.github/workflows/go-tests-windows.yml

@@ -41,6 +41,7 @@ jobs:
       run: |
       run: |
         go install github.com/kyoh86/richgo@v0.3.10
         go install github.com/kyoh86/richgo@v0.3.10
         go test -coverprofile coverage.out -covermode=atomic ./... > out.txt
         go test -coverprofile coverage.out -covermode=atomic ./... > out.txt
+        if(!$?) { cat out.txt | sed 's/ *coverage:.*of statements in.*//' | richgo testfilter; Exit 1 }
         cat out.txt | sed 's/ *coverage:.*of statements in.*//' | richgo testfilter
         cat out.txt | sed 's/ *coverage:.*of statements in.*//' | richgo testfilter
 
 
     - name: Upload unit coverage to Codecov
     - name: Upload unit coverage to Codecov

+ 6 - 1
pkg/acquisition/modules/file/file_test.go

@@ -460,7 +460,12 @@ exclude_regexps: ["\\.gz$"]`
 	if err != nil {
 	if err != nil {
 		subLogger.Fatalf("unexpected error: %s", err)
 		subLogger.Fatalf("unexpected error: %s", err)
 	}
 	}
-	expectedLogOutput := "Skipping file test_files/test.log.gz as it matches exclude pattern"
+	var expectedLogOutput string
+	if runtime.GOOS == "windows" {
+		expectedLogOutput = "Skipping file test_files\\test.log.gz as it matches exclude pattern \\.gz"
+	} else {
+		expectedLogOutput = "Skipping file test_files/test.log.gz as it matches exclude pattern"
+	}
 	if hook.LastEntry() == nil {
 	if hook.LastEntry() == nil {
 		t.Fatalf("expected output %s, but got nothing", expectedLogOutput)
 		t.Fatalf("expected output %s, but got nothing", expectedLogOutput)
 	}
 	}

+ 7 - 0
pkg/acquisition/modules/kafka/kafka_test.go

@@ -3,6 +3,7 @@ package kafkaacquisition
 import (
 import (
 	"context"
 	"context"
 	"net"
 	"net"
+	"runtime"
 	"strconv"
 	"strconv"
 	"testing"
 	"testing"
 	"time"
 	"time"
@@ -114,6 +115,9 @@ func createTopic(topic string, broker string) {
 }
 }
 
 
 func TestStreamingAcquisition(t *testing.T) {
 func TestStreamingAcquisition(t *testing.T) {
+	if runtime.GOOS == "windows" {
+		t.Skip("Skipping test on windows")
+	}
 	tests := []struct {
 	tests := []struct {
 		name          string
 		name          string
 		logs          []string
 		logs          []string
@@ -181,6 +185,9 @@ topic: crowdsecplaintext`), subLogger)
 }
 }
 
 
 func TestStreamingAcquisitionWithSSL(t *testing.T) {
 func TestStreamingAcquisitionWithSSL(t *testing.T) {
+	if runtime.GOOS == "windows" {
+		t.Skip("Skipping test on windows")
+	}
 	tests := []struct {
 	tests := []struct {
 		name          string
 		name          string
 		logs          []string
 		logs          []string

+ 4 - 5
pkg/database/database.go

@@ -61,7 +61,6 @@ func NewClient(config *csconfig.DatabaseCfg) (*Client, error) {
 	entOpt := ent.Log(entLogger.Debug)
 	entOpt := ent.Log(entLogger.Debug)
 	switch config.Type {
 	switch config.Type {
 	case "sqlite":
 	case "sqlite":
-
 		/*if it's the first startup, we want to touch and chmod file*/
 		/*if it's the first startup, we want to touch and chmod file*/
 		if _, err := os.Stat(config.DbPath); os.IsNotExist(err) {
 		if _, err := os.Stat(config.DbPath); os.IsNotExist(err) {
 			f, err := os.OpenFile(config.DbPath, os.O_CREATE|os.O_RDWR, 0600)
 			f, err := os.OpenFile(config.DbPath, os.O_CREATE|os.O_RDWR, 0600)
@@ -71,10 +70,10 @@ func NewClient(config *csconfig.DatabaseCfg) (*Client, error) {
 			if err := f.Close(); err != nil {
 			if err := f.Close(); err != nil {
 				return &Client{}, errors.Wrapf(err, "failed to create SQLite database file %q", config.DbPath)
 				return &Client{}, errors.Wrapf(err, "failed to create SQLite database file %q", config.DbPath)
 			}
 			}
-		} else { /*ensure file perms*/
-			if err := os.Chmod(config.DbPath, 0660); err != nil {
-				return &Client{}, fmt.Errorf("unable to set perms on %s: %v", config.DbPath, err)
-			}
+		}
+		//Always try to set permissions to simplify a bit the code for windows (as the permissions set by OpenFile will be garbage)
+		if err := setFilePerm(config.DbPath, 0600); err != nil {
+			return &Client{}, fmt.Errorf("unable to set perms on %s: %v", config.DbPath, err)
 		}
 		}
 		if config.UseWal == nil {
 		if config.UseWal == nil {
 			entLogger.Warn("you are using sqlite without WAL, this can have an impact of performance. If you do not store the database in a network share, set db_config.use_wal to true. Set explicitly to false to disable this warning.")
 			entLogger.Warn("you are using sqlite without WAL, this can have an impact of performance. If you do not store the database in a network share, set db_config.use_wal to true. Set explicitly to false to disable this warning.")

+ 12 - 0
pkg/database/file_utils.go

@@ -0,0 +1,12 @@
+//go:build !windows
+
+package database
+
+import (
+	"io/fs"
+	"os"
+)
+
+func setFilePerm(path string, mode fs.FileMode) error {
+	return os.Chmod(path, mode)
+}

+ 79 - 0
pkg/database/file_utils_windows.go

@@ -0,0 +1,79 @@
+package database
+
+import (
+	"fmt"
+	"io/fs"
+
+	log "github.com/sirupsen/logrus"
+	"golang.org/x/sys/windows"
+)
+
+func setFilePerm(path string, mode fs.FileMode) error {
+	//On windows, we don't care about the mode, just make sure the file is only readable/writable by the owner and group
+
+	sd, err := windows.GetNamedSecurityInfo(path, windows.SE_FILE_OBJECT, windows.OWNER_SECURITY_INFORMATION)
+	if err != nil {
+		return fmt.Errorf("while getting security info: %w", err)
+	}
+
+	currentOwner, defaulted, err := sd.Owner()
+
+	if err != nil {
+		return fmt.Errorf("while getting owner: %w", err)
+	}
+
+	log.Debugf("current owner is %s (%v) (defaulted: %v)", currentOwner.String(), currentOwner, defaulted)
+
+	currentGroup, defaulted, err := sd.Group()
+
+	if err != nil {
+		return fmt.Errorf("while getting group: %w", err)
+	}
+
+	if currentGroup == nil {
+		log.Debugf("current group is nil (defaulted: %v), using builtin admin instead", defaulted)
+		currentGroup, err = windows.CreateWellKnownSid(windows.WinBuiltinAdministratorsSid)
+		if err != nil {
+			return fmt.Errorf("while creating admin SID: %w", err)
+		}
+	}
+
+	log.Debugf("current group is %s (%v) (defaulted: %v)", currentGroup.String(), currentGroup, defaulted)
+
+	dacl, err := windows.ACLFromEntries(
+		[]windows.EXPLICIT_ACCESS{
+			{
+				AccessPermissions: windows.GENERIC_ALL,
+				AccessMode:        windows.GRANT_ACCESS,
+				Inheritance:       windows.NO_INHERITANCE,
+				Trustee: windows.TRUSTEE{
+					MultipleTrusteeOperation: windows.NO_MULTIPLE_TRUSTEE,
+					TrusteeForm:              windows.TRUSTEE_IS_SID,
+					TrusteeType:              windows.TRUSTEE_IS_USER,
+					TrusteeValue:             windows.TrusteeValueFromSID(currentOwner),
+				},
+			},
+			{
+				AccessPermissions: windows.GENERIC_ALL,
+				AccessMode:        windows.GRANT_ACCESS,
+				Inheritance:       windows.NO_INHERITANCE,
+				Trustee: windows.TRUSTEE{
+					MultipleTrusteeOperation: windows.NO_MULTIPLE_TRUSTEE,
+					TrusteeForm:              windows.TRUSTEE_IS_SID,
+					TrusteeType:              windows.TRUSTEE_IS_GROUP,
+					TrusteeValue:             windows.TrusteeValueFromSID(currentGroup),
+				},
+			},
+		}, nil)
+
+	if err != nil {
+		return fmt.Errorf("while creating ACL: %w", err)
+	}
+
+	err = windows.SetNamedSecurityInfo(path, windows.SE_FILE_OBJECT, windows.DACL_SECURITY_INFORMATION|windows.PROTECTED_DACL_SECURITY_INFORMATION, nil, nil, dacl, nil)
+
+	if err != nil {
+		return fmt.Errorf("while setting security info: %w", err)
+	}
+	return nil
+}