mirror of
https://github.com/netbirdio/netbird.git
synced 2026-07-23 17:01:29 +02:00
54 lines
1.6 KiB
Go
54 lines
1.6 KiB
Go
package server
|
|
|
|
import (
|
|
"context"
|
|
"runtime"
|
|
"strings"
|
|
|
|
log "github.com/sirupsen/logrus"
|
|
"google.golang.org/grpc/codes"
|
|
gstatus "google.golang.org/grpc/status"
|
|
|
|
"github.com/netbirdio/netbird/client/internal/ipcauth"
|
|
)
|
|
|
|
// bindCallerUsername enforces that a non-privileged caller may only operate on
|
|
// its OWN user's profiles. Profiles live in per-username directories, but the
|
|
// username is a client-supplied gRPC field the server historically never
|
|
// checked; binding it to the caller's kernel identity closes the "pass another
|
|
// user's username" hole. Privileged callers (root / elevated-admin) may manage
|
|
// any user's profiles.
|
|
func (s *Server) bindCallerUsername(ctx context.Context, requested string) error {
|
|
if requested == "" {
|
|
return nil // handlers validate emptiness themselves; nothing to bind
|
|
}
|
|
|
|
id, ok := ipcauth.IdentityFromContext(ctx)
|
|
if !ok {
|
|
return gstatus.Error(codes.PermissionDenied, "caller identity could not be verified")
|
|
}
|
|
if id.IsPrivileged() {
|
|
return nil
|
|
}
|
|
|
|
caller, err := usernameForIdentity(id)
|
|
if err != nil {
|
|
log.Warnf("profile authz: resolve caller username for %s: %v", id, err)
|
|
return gstatus.Error(codes.PermissionDenied, "could not resolve caller identity to a username")
|
|
}
|
|
if !usernamesEqual(requested, caller) {
|
|
return gstatus.Errorf(codes.PermissionDenied,
|
|
"not authorized to operate on another user's profiles (caller %q requested %q)", caller, requested)
|
|
}
|
|
return nil
|
|
}
|
|
|
|
// usernamesEqual compares usernames case-insensitively on Windows (domain
|
|
// accounts) and exactly on Unix.
|
|
func usernamesEqual(a, b string) bool {
|
|
if runtime.GOOS == "windows" {
|
|
return strings.EqualFold(a, b)
|
|
}
|
|
return a == b
|
|
}
|