From 6970edae13f38d95e04ae39f4f2393ba35920710 Mon Sep 17 00:00:00 2001 From: Joe Reuss Date: Wed, 27 Sep 2023 18:16:10 +0000 Subject: [PATCH] Fixed Generate Private Key Problems in Windows Found an issue when trying to get a private key when running my unit test locally on my windows machine. From investigating found that privs.go only worked with uid's and gid's which is only functional with mac and linux. I modified a few things to work with windows SID's as well by checking what os is being ran. I ran my tests after modifying on both my linux container and locally on windows and it seems to work now. I also had to change around a few lines in GeneratePrivateKey since it calls a "chown" which is not a windows command. --- config/init_server_creds.go | 23 +++++++++++-- config/privs.go | 69 ++++++++++++++++++++++++++----------- 2 files changed, 68 insertions(+), 24 deletions(-) diff --git a/config/init_server_creds.go b/config/init_server_creds.go index 5077feb9a..0d2987e59 100644 --- a/config/init_server_creds.go +++ b/config/init_server_creds.go @@ -28,7 +28,9 @@ import ( "fmt" "math/big" "os" + "os/exec" "path/filepath" + "runtime" "sync/atomic" "time" @@ -194,6 +196,10 @@ func GeneratePrivateKey(keyLocation string, curve elliptic.Curve) error { if err != nil { return err } + user, err := GetDaemonUser() + if err != nil { + return err + } groupname, err := GetDaemonGroup() if err != nil { return err @@ -219,9 +225,20 @@ func GeneratePrivateKey(keyLocation string, curve elliptic.Curve) error { if err != nil { return err } - if err = os.Chown(keyLocation, uid, gid); err != nil { - return errors.Wrapf(err, "Failed to chown generated key %v to daemon group %v", - keyLocation, groupname) + // Windows does not have "chown", has to work differently + currentOS := runtime.GOOS + if currentOS == "windows" { + cmd := exec.Command("icacls", keyLocation, "/grant", user+":F") + output, err := cmd.CombinedOutput() + if err != nil { + return errors.Wrapf(err, "Failed to chown generated key %v to daemon group %v: %s", + keyLocation, groupname, string(output)) + } + } else { // Else we are running on linux/mac + if err = os.Chown(keyLocation, uid, gid); err != nil { + return errors.Wrapf(err, "Failed to chown generated key %v to daemon group %v", + keyLocation, groupname) + } } bytes, err := x509.MarshalPKCS8PrivateKey(priv) diff --git a/config/privs.go b/config/privs.go index 0134ee207..34d9a3c31 100644 --- a/config/privs.go +++ b/config/privs.go @@ -20,7 +20,9 @@ package config import ( "os/user" + "runtime" "strconv" + "strings" "github.com/pkg/errors" ) @@ -30,11 +32,13 @@ var ( uidErr error gidErr error + sidErr error usernameErr error groupErr error uid int gid int + sid string username string group string ) @@ -45,9 +49,11 @@ func init() { uid = -1 gid = -1 + sid = "" if err != nil { uidErr = err gidErr = err + sidErr = err usernameErr = err groupErr = err return @@ -66,29 +72,46 @@ func init() { return } } - username = desiredUsername - uid, err = strconv.Atoi(userObj.Uid) - if err != nil { - uid = -1 - uidErr = err - } - gid, err = strconv.Atoi(userObj.Gid) - if err != nil { - gid = -1 - gidErr = err - } - groupObj, err := user.LookupGroupId(userObj.Gid) - if err == nil { - group = groupObj.Name - } else { - // Fall back to using the GID as the group name. This is done because, - // currently, the group name is just for logging strings. The group name - // lookup often fails because we've disabled CGO and only CGO will use the - // full glibc stack to resolve information via SSSD. - // - // This decision should be revisited if we ever enable CGO. + //Windows has userId's different from mac and linux, need to parse to get it + currentOS := runtime.GOOS + if currentOS == "windows" { + //Get the user ID from the SID + sidParts := strings.Split(userObj.Uid, "-") + uidString := sidParts[len(sidParts)-1] + uid, err = strconv.Atoi(uidString) + if err != nil { + uid = -1 + uidErr = err + } + sid = userObj.Gid + //group is just the whole SID group = userObj.Gid + } else { //Mac and linux have similar enough uid's so can group them here + uid, err = strconv.Atoi(userObj.Uid) + if err != nil { + uid = -1 + uidErr = err + } + gid, err = strconv.Atoi(userObj.Gid) + if err != nil { + gid = -1 + gidErr = err + } + groupObj, err := user.LookupGroupId(userObj.Gid) + if err == nil { + group = groupObj.Name + } else { + // Fall back to using the GID as the group name. This is done because, + // currently, the group name is just for logging strings. The group name + // lookup often fails because we've disabled CGO and only CGO will use the + // full glibc stack to resolve information via SSSD. + // + // This decision should be revisited if we ever enable CGO. + group = userObj.Gid + } } + // username same for both windows, linux, and mac + username = desiredUsername } func IsRootExecution() bool { @@ -107,6 +130,10 @@ func GetDaemonGID() (int, error) { return gid, gidErr } +func GetDaemonSID() (string, error) { + return sid, sidErr +} + func GetDaemonGroup() (string, error) { return group, groupErr }