Kaynağa Gözat

Tighten windows sqlite database permissions (#1769)

blotus 2 yıl önce
ebeveyn
işleme
bfbe180101

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

@@ -41,6 +41,7 @@ jobs:
       run: |
         go install github.com/kyoh86/richgo@v0.3.10
         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
 
     - 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 {
 		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 {
 		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 (
 	"context"
 	"net"
+	"runtime"
 	"strconv"
 	"testing"
 	"time"
@@ -114,6 +115,9 @@ func createTopic(topic string, broker string) {
 }
 
 func TestStreamingAcquisition(t *testing.T) {
+	if runtime.GOOS == "windows" {
+		t.Skip("Skipping test on windows")
+	}
 	tests := []struct {
 		name          string
 		logs          []string
@@ -181,6 +185,9 @@ topic: crowdsecplaintext`), subLogger)
 }
 
 func TestStreamingAcquisitionWithSSL(t *testing.T) {
+	if runtime.GOOS == "windows" {
+		t.Skip("Skipping test on windows")
+	}
 	tests := []struct {
 		name          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)
 	switch config.Type {
 	case "sqlite":
-
 		/*if it's the first startup, we want to touch and chmod file*/
 		if _, err := os.Stat(config.DbPath); os.IsNotExist(err) {
 			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 {
 				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 {
 			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
+}