-
Notifications
You must be signed in to change notification settings - Fork 18.9k
os/user: Lookup does not handle windows.ERROR_NONE_MAPPED correctly #73595
Description
Go version
1.23.1, windows/amd64
Output of go env in your module/workspace:
AR='ar'
CC='gcc'
CGO_CFLAGS='-O2 -g'
CGO_CPPFLAGS=''
CGO_CXXFLAGS='-O2 -g'
CGO_ENABLED='1'
CGO_FFLAGS='-O2 -g'
CGO_LDFLAGS='-O2 -g'
CXX='g++'
GCCGO='gccgo'
GO111MODULE='on'
GOAMD64='v1'
GOARCH='amd64'
GOAUTH='netrc'
GOBIN=''
GOCACHE='/home/jma/.cache/go-build'
GOCACHEPROG=''
GODEBUG=''
GOENV='/home/jma/.config/go/env'
GOEXE=''
GOEXPERIMENT=''
GOFIPS140='off'
GOFLAGS=''
GOGCCFLAGS='-fPIC -m64 -pthread -Wl,--no-gc-sections -fmessage-length=0 -ffile-prefix-map=/tmp/go-build134067901=/tmp/go-build -gno-record-gcc-switches'
GOHOSTARCH='amd64'
GOHOSTOS='linux'
GOINSECURE=''
GOMOD='/home/jma/goShared/go-utils/go.mod'
GOMODCACHE='/home/jma/.gvm/pkgsets/go1.24.1/global/pkg/mod'
GOOS='linux'
GOPATH='/home/jma/.gvm/pkgsets/go1.24.1/global'
GOPROXY='https://proxy.golang.org,direct'
GOROOT='/home/jma/.gvm/gos/go1.24.1'
GOSUMDB='sum.golang.org'
GOTELEMETRY='local'
GOTELEMETRYDIR='/home/jma/.config/go/telemetry'
GOTMPDIR=''
GOTOOLCHAIN='auto'
GOTOOLDIR='/home/jma/.gvm/gos/go1.24.1/pkg/tool/linux_amd64'
GOVCS=''
GOVERSION='go1.24.1'
GOWORK=''
PKG_CONFIG='pkg-config'What did you do?
The godoc of os/user.Lookup states the following:
// Lookup looks up a user by username. If the user cannot be found, the
// returned error is of type [UnknownUserError].
However, this is not correct on Windows. When tested on Windows Server 2016 / Windows Server 2019 / Windows Server 2022, the Lookup-method fails with the following error message:
No mapping between account names and security IDs was done.
I expected the function to return user.UnknownUserError.
The error message stems from the Windows Error Code windows.ERROR_NONE_MAPPED - which specifically states that the account name does not exist.
I tried to manually detect this specific error situation with the following workaround:
func CheckUsernameExists(username string) (bool, error) {
_, err := user.Lookup(username)
if err == nil {
return true, nil // user exists
}
if _, ok := err.(user.UnknownUserError); ok {
return false, nil // user does not exist
}
// Workaround:
var sysErr syscall.Errno
if ok := errors.As(err, &sysErr); ok && sysErr == windows.ERROR_NONE_MAPPED { // "No mapping between account names and security IDs was done."
return false, nil // does not exist
}
return false, err // unknown error
}
However, this does not work either, because user.Lookup does not "wrap" the underlying error (it uses %v instead of %w - also for other target platforms).
What did you see happen?
user.Lookup should return user.UnknownUserError if Windows produces windows.ERROR_NONE_MAPPED.
user.Lookup should also wrap underlying system errors, so that error codes can be inspected.
What did you expect to see?
user.Lookup embeds the windows error message (string) into the returned error message.