Files
netbird/client/internal/ipcauth/forward.go
2026-07-23 14:14:42 +02:00

73 lines
1.8 KiB
Go

package ipcauth
import (
"context"
"strconv"
"google.golang.org/grpc/metadata"
)
// Metadata keys used by the local JSON gateway to forward the HTTP client's
// identity to the daemon. Trusted by the interceptor ONLY when the gRPC peer is
// itself the daemon (self/privileged) — i.e. the loopback gateway — so a direct
// gRPC caller cannot forge them.
const (
mdFwdUID = "x-netbird-fwd-uid"
mdFwdGID = "x-netbird-fwd-gid"
mdFwdPID = "x-netbird-fwd-pid"
)
// ForwardIdentityMetadata encodes a Unix identity for the gateway to forward to
// the daemon. Windows identities are not forwarded (the gateway cannot read a
// pipe token for an HTTP client); nil is returned in that case.
func ForwardIdentityMetadata(id Identity) metadata.MD {
if id.IsWindows() {
return nil
}
md := metadata.Pairs(
mdFwdUID, strconv.FormatUint(uint64(id.UID), 10),
mdFwdGID, strconv.FormatUint(uint64(id.GID), 10),
)
if id.HasPID {
md.Set(mdFwdPID, strconv.FormatInt(int64(id.PID), 10))
}
return md
}
// forwardedIdentity extracts a forwarded Unix identity from incoming gRPC
// metadata, if present and well-formed.
func forwardedIdentity(ctx context.Context) (Identity, bool) {
md, ok := metadata.FromIncomingContext(ctx)
if !ok {
return Identity{}, false
}
uidStr := mdFirst(md, mdFwdUID)
if uidStr == "" {
return Identity{}, false
}
uid, err := strconv.ParseUint(uidStr, 10, 32)
if err != nil {
return Identity{}, false
}
id := Identity{UID: uint32(uid)}
if g := mdFirst(md, mdFwdGID); g != "" {
if v, err := strconv.ParseUint(g, 10, 32); err == nil {
id.GID = uint32(v)
}
}
if p := mdFirst(md, mdFwdPID); p != "" {
if v, err := strconv.ParseInt(p, 10, 32); err == nil {
id.PID = int32(v)
id.HasPID = true
}
}
return id, true
}
func mdFirst(md metadata.MD, key string) string {
if v := md.Get(key); len(v) > 0 {
return v[0]
}
return ""
}