[lxc-devel] [lxd/master] Log username on unix queries

stgraber on Github lxc-bot at linuxcontainers.org
Tue Oct 27 23:11:21 UTC 2020


A non-text attachment was scrubbed...
Name: not available
Type: text/x-mailbox
Size: 301 bytes
Desc: not available
URL: <http://lists.linuxcontainers.org/pipermail/lxc-devel/attachments/20201027/53cf85c0/attachment.bin>
-------------- next part --------------
From f3c4805b2267aa6e8af890499ee8c72673522b77 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?St=C3=A9phane=20Graber?= <stgraber at ubuntu.com>
Date: Tue, 27 Oct 2020 18:56:45 -0400
Subject: [PATCH 1/5] shared: Drop GroupId and UserId
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit

Signed-off-by: Stéphane Graber <stgraber at ubuntu.com>
---
 shared/util_linux_cgo.go | 97 ----------------------------------------
 1 file changed, 97 deletions(-)

diff --git a/shared/util_linux_cgo.go b/shared/util_linux_cgo.go
index 72d0794953..155975d265 100644
--- a/shared/util_linux_cgo.go
+++ b/shared/util_linux_cgo.go
@@ -6,7 +6,6 @@ package shared
 import (
 	"fmt"
 	"os"
-	"unsafe"
 
 	// Used by cgo
 	_ "github.com/lxc/lxd/lxd/include"
@@ -58,102 +57,6 @@ import "C"
 
 const ABSTRACT_UNIX_SOCK_LEN int = C.ABSTRACT_UNIX_SOCK_LEN
 
-// UserId is an adaption from https://codereview.appspot.com/4589049.
-func UserId(name string) (int, error) {
-	var pw C.struct_passwd
-	var result *C.struct_passwd
-
-	bufSize := C.sysconf(C._SC_GETPW_R_SIZE_MAX)
-	if bufSize < 0 {
-		bufSize = 4096
-	}
-
-	buf := C.malloc(C.size_t(bufSize))
-	if buf == nil {
-		return -1, fmt.Errorf("allocation failed")
-	}
-	defer C.free(buf)
-
-	cname := C.CString(name)
-	defer C.free(unsafe.Pointer(cname))
-
-again:
-	rv, errno := C.getpwnam_r(cname,
-		&pw,
-		(*C.char)(buf),
-		C.size_t(bufSize),
-		&result)
-	if rv < 0 {
-		// OOM killer will take care of us if we end up doing this too
-		// often.
-		if errno == unix.ERANGE {
-			bufSize *= 2
-			tmp := C.realloc(buf, C.size_t(bufSize))
-			if tmp == nil {
-				return -1, fmt.Errorf("allocation failed")
-			}
-			buf = tmp
-			goto again
-		}
-		return -1, fmt.Errorf("failed user lookup: %s", unix.Errno(rv))
-	}
-
-	if result == nil {
-		return -1, fmt.Errorf("unknown user %s", name)
-	}
-
-	return int(C.int(result.pw_uid)), nil
-}
-
-// GroupId is an adaption from https://codereview.appspot.com/4589049.
-func GroupId(name string) (int, error) {
-	var grp C.struct_group
-	var result *C.struct_group
-
-	bufSize := C.sysconf(C._SC_GETGR_R_SIZE_MAX)
-	if bufSize < 0 {
-		bufSize = 4096
-	}
-
-	buf := C.malloc(C.size_t(bufSize))
-	if buf == nil {
-		return -1, fmt.Errorf("allocation failed")
-	}
-
-	cname := C.CString(name)
-	defer C.free(unsafe.Pointer(cname))
-
-again:
-	rv, errno := C.getgrnam_r(cname,
-		&grp,
-		(*C.char)(buf),
-		C.size_t(bufSize),
-		&result)
-	if rv != 0 {
-		// OOM killer will take care of us if we end up doing this too
-		// often.
-		if errno == unix.ERANGE {
-			bufSize *= 2
-			tmp := C.realloc(buf, C.size_t(bufSize))
-			if tmp == nil {
-				return -1, fmt.Errorf("allocation failed")
-			}
-			buf = tmp
-			goto again
-		}
-
-		C.free(buf)
-		return -1, fmt.Errorf("failed group lookup: %s", unix.Errno(rv))
-	}
-	C.free(buf)
-
-	if result == nil {
-		return -1, fmt.Errorf("unknown group %s", name)
-	}
-
-	return int(C.int(result.gr_gid)), nil
-}
-
 func ReadPid(r *os.File) int {
 	return int(C.read_pid(C.int(r.Fd())))
 }

From 30e814b42b0a19355c2bad3a2e971c7bf44c5f5b Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?St=C3=A9phane=20Graber?= <stgraber at ubuntu.com>
Date: Tue, 27 Oct 2020 18:57:23 -0400
Subject: [PATCH 2/5] lxd: Port to os/user
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit

Signed-off-by: Stéphane Graber <stgraber at ubuntu.com>
---
 lxd/endpoints/socket.go | 14 ++++++++++----
 lxd/sys/os.go           | 24 ++++++++++++++++++------
 2 files changed, 28 insertions(+), 10 deletions(-)

diff --git a/lxd/endpoints/socket.go b/lxd/endpoints/socket.go
index 6eeccba3fc..98a81a2646 100644
--- a/lxd/endpoints/socket.go
+++ b/lxd/endpoints/socket.go
@@ -6,6 +6,7 @@ import (
 	"fmt"
 	"net"
 	"os"
+	"os/user"
 	"strconv"
 
 	"github.com/lxc/lxd/client"
@@ -86,14 +87,19 @@ func socketUnixSetPermissions(path string, mode os.FileMode) error {
 }
 
 // Change the ownership of the given unix socket file,
-func socketUnixSetOwnership(path string, group string) error {
+func socketUnixSetOwnership(path string, groupName string) error {
 	var gid int
 	var err error
 
-	if group != "" {
-		gid, err = shared.GroupId(group)
+	if groupName != "" {
+		g, err := user.LookupGroup(groupName)
 		if err != nil {
-			return fmt.Errorf("cannot get group ID of '%s': %v", group, err)
+			return fmt.Errorf("cannot get group ID of '%s': %v", groupName, err)
+		}
+
+		gid, err = strconv.Atoi(g.Gid)
+		if err != nil {
+			return err
 		}
 	} else {
 		gid = os.Getgid()
diff --git a/lxd/sys/os.go b/lxd/sys/os.go
index 61cdf47394..0ab6d8f281 100644
--- a/lxd/sys/os.go
+++ b/lxd/sys/os.go
@@ -3,7 +3,9 @@
 package sys
 
 import (
+	"os/user"
 	"path/filepath"
+	"strconv"
 	"sync"
 
 	log "github.com/lxc/lxd/shared/log15"
@@ -115,24 +117,34 @@ func (s *OS) Init() error {
 	}
 
 	// Detect if it is possible to run daemons as an unprivileged user and group.
-	for _, user := range []string{"lxd", "nobody"} {
-		uid, err := shared.UserId(user)
+	for _, userName := range []string{"lxd", "nobody"} {
+		u, err := user.Lookup(userName)
 		if err != nil {
 			continue
 		}
 
-		s.UnprivUser = user
+		uid, err := strconv.ParseUint(u.Uid, 10, 32)
+		if err != nil {
+			return err
+		}
+
+		s.UnprivUser = userName
 		s.UnprivUID = uint32(uid)
 		break
 	}
 
-	for _, group := range []string{"lxd", "nogroup"} {
-		gid, err := shared.GroupId(group)
+	for _, groupName := range []string{"lxd", "nogroup"} {
+		g, err := user.LookupGroup(groupName)
 		if err != nil {
 			continue
 		}
 
-		s.UnprivGroup = group
+		gid, err := strconv.ParseUint(g.Gid, 10, 32)
+		if err != nil {
+			return err
+		}
+
+		s.UnprivGroup = groupName
 		s.UnprivGID = uint32(gid)
 		break
 	}

From a38f4092d40c68c77a704353776bf7edce98edd2 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?St=C3=A9phane=20Graber?= <stgraber at ubuntu.com>
Date: Tue, 27 Oct 2020 19:07:58 -0400
Subject: [PATCH 3/5] lxd/daemon: Log protocol
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit

Signed-off-by: Stéphane Graber <stgraber at ubuntu.com>
---
 lxd/daemon.go | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/lxd/daemon.go b/lxd/daemon.go
index 52308da8c3..1de4938c70 100644
--- a/lxd/daemon.go
+++ b/lxd/daemon.go
@@ -425,7 +425,7 @@ func (d *Daemon) createCmd(restAPI *mux.Router, version string, c APIEndpoint) {
 
 		untrustedOk := (r.Method == "GET" && c.Get.AllowUntrusted) || (r.Method == "POST" && c.Post.AllowUntrusted)
 		if trusted {
-			logger.Debug("Handling", log.Ctx{"method": r.Method, "url": r.URL.RequestURI(), "ip": r.RemoteAddr, "user": username})
+			logger.Debug("Handling", log.Ctx{"method": r.Method, "url": r.URL.RequestURI(), "ip": r.RemoteAddr, "username": username, "protocol": protocol})
 			r = r.WithContext(context.WithValue(context.WithValue(r.Context(), "username", username), "protocol", protocol))
 		} else if untrustedOk && r.Header.Get("X-LXD-authenticated") == "" {
 			logger.Debug(fmt.Sprintf("Allowing untrusted %s", r.Method), log.Ctx{"url": r.URL.RequestURI(), "ip": r.RemoteAddr})

From 1694cfd678f4eadeddda4831f3103a1d3aaed439 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?St=C3=A9phane=20Graber?= <stgraber at ubuntu.com>
Date: Tue, 27 Oct 2020 19:08:35 -0400
Subject: [PATCH 4/5] lxd/daemon: Pass writer to Authenticate
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit

Signed-off-by: Stéphane Graber <stgraber at ubuntu.com>
---
 lxd/certificates.go | 2 +-
 lxd/daemon.go       | 6 +++---
 lxd/images.go       | 2 +-
 lxd/operations.go   | 2 +-
 4 files changed, 6 insertions(+), 6 deletions(-)

diff --git a/lxd/certificates.go b/lxd/certificates.go
index 917f5d1178..673ae5a386 100644
--- a/lxd/certificates.go
+++ b/lxd/certificates.go
@@ -125,7 +125,7 @@ func certificatesPost(d *Daemon, r *http.Request) response.Response {
 		return response.SmartError(err)
 	}
 
-	trusted, _, protocol, err := d.Authenticate(r)
+	trusted, _, protocol, err := d.Authenticate(nil, r)
 	if err != nil {
 		return response.SmartError(err)
 	}
diff --git a/lxd/daemon.go b/lxd/daemon.go
index 1de4938c70..94f6728b1c 100644
--- a/lxd/daemon.go
+++ b/lxd/daemon.go
@@ -241,7 +241,7 @@ func allowProjectPermission(feature string, permission string) func(d *Daemon, r
 
 // Convenience function around Authenticate
 func (d *Daemon) checkTrustedClient(r *http.Request) error {
-	trusted, _, _, err := d.Authenticate(r)
+	trusted, _, _, err := d.Authenticate(nil, r)
 	if !trusted || err != nil {
 		if err != nil {
 			return err
@@ -258,7 +258,7 @@ func (d *Daemon) checkTrustedClient(r *http.Request) error {
 // will validate the TLS certificate or Macaroon.
 //
 // This does not perform authorization, only validates authentication
-func (d *Daemon) Authenticate(r *http.Request) (bool, string, string, error) {
+func (d *Daemon) Authenticate(w http.ResponseWriter, r *http.Request) (bool, string, string, error) {
 	// Allow internal cluster traffic
 	if r.TLS != nil {
 		cert, _ := x509.ParseCertificate(d.endpoints.NetworkCert().KeyPair().Certificate[0])
@@ -403,7 +403,7 @@ func (d *Daemon) createCmd(restAPI *mux.Router, version string, c APIEndpoint) {
 		}
 
 		// Authentication
-		trusted, username, protocol, err := d.Authenticate(r)
+		trusted, username, protocol, err := d.Authenticate(w, r)
 		if err != nil {
 			// If not a macaroon discharge request, return the error
 			_, ok := err.(*bakery.DischargeRequiredError)
diff --git a/lxd/images.go b/lxd/images.go
index d97e759408..4fb55b9087 100644
--- a/lxd/images.go
+++ b/lxd/images.go
@@ -696,7 +696,7 @@ func imageCreateInPool(d *Daemon, info *api.Image, storagePool string) error {
 }
 
 func imagesPost(d *Daemon, r *http.Request) response.Response {
-	trusted, _, _, _ := d.Authenticate(r)
+	trusted, _, _, _ := d.Authenticate(nil, r)
 
 	secret := r.Header.Get("X-LXD-secret")
 	fingerprint := r.Header.Get("X-LXD-fingerprint")
diff --git a/lxd/operations.go b/lxd/operations.go
index e5d934c9ed..b46427f1cf 100644
--- a/lxd/operations.go
+++ b/lxd/operations.go
@@ -372,7 +372,7 @@ func operationWaitGet(d *Daemon, r *http.Request) response.Response {
 	id := mux.Vars(r)["id"]
 	secret := r.FormValue("secret")
 
-	trusted, _, _, _ := d.Authenticate(r)
+	trusted, _, _, _ := d.Authenticate(nil, r)
 	if !trusted && secret == "" {
 		return response.Forbidden(nil)
 	}

From e5a01555ba6d1e25ce859be84a5b9b9d4a88b8ff Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?St=C3=A9phane=20Graber?= <stgraber at ubuntu.com>
Date: Tue, 27 Oct 2020 19:08:53 -0400
Subject: [PATCH 5/5] lxd/daemon: Record username on unix queries
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit

Closes #8012

Signed-off-by: Stéphane Graber <stgraber at ubuntu.com>
---
 lxd/daemon.go | 17 +++++++++++++++++
 1 file changed, 17 insertions(+)

diff --git a/lxd/daemon.go b/lxd/daemon.go
index 94f6728b1c..8e8cd12c20 100644
--- a/lxd/daemon.go
+++ b/lxd/daemon.go
@@ -11,6 +11,7 @@ import (
 	"net/http"
 	"net/url"
 	"os"
+	"os/user"
 	"path/filepath"
 	"strings"
 	"sync"
@@ -37,6 +38,7 @@ import (
 	"github.com/lxc/lxd/lxd/events"
 	"github.com/lxc/lxd/lxd/firewall"
 	"github.com/lxc/lxd/lxd/instance"
+	"github.com/lxc/lxd/lxd/ucred"
 
 	// Import instance/drivers without name so init() runs.
 	_ "github.com/lxc/lxd/lxd/instance/drivers"
@@ -273,6 +275,21 @@ func (d *Daemon) Authenticate(w http.ResponseWriter, r *http.Request) (bool, str
 
 	// Local unix socket queries
 	if r.RemoteAddr == "@" {
+		if w != nil {
+			conn := extractUnderlyingConn(w)
+			cred, err := ucred.GetCred(conn)
+			if err != nil {
+				return false, "", "", err
+			}
+
+			u, err := user.LookupId(fmt.Sprintf("%d", cred.Uid))
+			if err != nil {
+				return true, fmt.Sprintf("uid=%d", cred.Uid), "unix", nil
+			}
+
+			return true, u.Username, "unix", nil
+		}
+
 		return true, "", "unix", nil
 	}
 


More information about the lxc-devel mailing list