aboutsummaryrefslogtreecommitdiffstats
path: root/contrib/go/_std_1.22/src/os/user
diff options
context:
space:
mode:
authorhiddenpath <hiddenpath@yandex-team.com>2024-04-02 23:50:23 +0300
committerhiddenpath <hiddenpath@yandex-team.com>2024-04-03 00:02:31 +0300
commit8923c6d2c438e0aeed2e06b8b0275e1864eeee33 (patch)
tree6b5e476699fc0be5091cb650654ef5f602c8afff /contrib/go/_std_1.22/src/os/user
parentd18afd09df2a08cd023012593b46109b77713a6c (diff)
downloadydb-8923c6d2c438e0aeed2e06b8b0275e1864eeee33.tar.gz
Update golang to 1.22.1
2967d19c907adf59101a1f47b4208bd0b04a6186
Diffstat (limited to 'contrib/go/_std_1.22/src/os/user')
-rw-r--r--contrib/go/_std_1.22/src/os/user/cgo_listgroups_unix.go57
-rw-r--r--contrib/go/_std_1.22/src/os/user/cgo_lookup_cgo.go112
-rw-r--r--contrib/go/_std_1.22/src/os/user/cgo_lookup_syscall.go65
-rw-r--r--contrib/go/_std_1.22/src/os/user/cgo_lookup_unix.go200
-rw-r--r--contrib/go/_std_1.22/src/os/user/getgrouplist_syscall.go19
-rw-r--r--contrib/go/_std_1.22/src/os/user/getgrouplist_unix.go22
-rw-r--r--contrib/go/_std_1.22/src/os/user/lookup.go70
-rw-r--r--contrib/go/_std_1.22/src/os/user/lookup_windows.go392
-rw-r--r--contrib/go/_std_1.22/src/os/user/user.go95
-rw-r--r--contrib/go/_std_1.22/src/os/user/ya.make40
10 files changed, 1072 insertions, 0 deletions
diff --git a/contrib/go/_std_1.22/src/os/user/cgo_listgroups_unix.go b/contrib/go/_std_1.22/src/os/user/cgo_listgroups_unix.go
new file mode 100644
index 0000000000..59636954b2
--- /dev/null
+++ b/contrib/go/_std_1.22/src/os/user/cgo_listgroups_unix.go
@@ -0,0 +1,57 @@
+// Copyright 2016 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+//go:build (cgo || darwin) && !osusergo && (darwin || dragonfly || freebsd || (linux && !android) || netbsd || openbsd || (solaris && !illumos))
+
+package user
+
+import (
+ "fmt"
+ "strconv"
+ "unsafe"
+)
+
+const maxGroups = 2048
+
+func listGroups(u *User) ([]string, error) {
+ ug, err := strconv.Atoi(u.Gid)
+ if err != nil {
+ return nil, fmt.Errorf("user: list groups for %s: invalid gid %q", u.Username, u.Gid)
+ }
+ userGID := _C_gid_t(ug)
+ nameC := make([]byte, len(u.Username)+1)
+ copy(nameC, u.Username)
+
+ n := _C_int(256)
+ gidsC := make([]_C_gid_t, n)
+ rv := getGroupList((*_C_char)(unsafe.Pointer(&nameC[0])), userGID, &gidsC[0], &n)
+ if rv == -1 {
+ // Mac is the only Unix that does not set n properly when rv == -1, so
+ // we need to use different logic for Mac vs. the other OS's.
+ if err := groupRetry(u.Username, nameC, userGID, &gidsC, &n); err != nil {
+ return nil, err
+ }
+ }
+ gidsC = gidsC[:n]
+ gids := make([]string, 0, n)
+ for _, g := range gidsC[:n] {
+ gids = append(gids, strconv.Itoa(int(g)))
+ }
+ return gids, nil
+}
+
+// groupRetry retries getGroupList with much larger size for n. The result is
+// stored in gids.
+func groupRetry(username string, name []byte, userGID _C_gid_t, gids *[]_C_gid_t, n *_C_int) error {
+ // More than initial buffer, but now n contains the correct size.
+ if *n > maxGroups {
+ return fmt.Errorf("user: %q is a member of more than %d groups", username, maxGroups)
+ }
+ *gids = make([]_C_gid_t, *n)
+ rv := getGroupList((*_C_char)(unsafe.Pointer(&name[0])), userGID, &(*gids)[0], n)
+ if rv == -1 {
+ return fmt.Errorf("user: list groups for %s failed", username)
+ }
+ return nil
+}
diff --git a/contrib/go/_std_1.22/src/os/user/cgo_lookup_cgo.go b/contrib/go/_std_1.22/src/os/user/cgo_lookup_cgo.go
new file mode 100644
index 0000000000..4f78dcad23
--- /dev/null
+++ b/contrib/go/_std_1.22/src/os/user/cgo_lookup_cgo.go
@@ -0,0 +1,112 @@
+// Copyright 2011 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+//go:build cgo && !osusergo && unix && !android && !darwin
+
+package user
+
+import (
+ "syscall"
+)
+
+/*
+#cgo solaris CFLAGS: -D_POSIX_PTHREAD_SEMANTICS
+#cgo CFLAGS: -fno-stack-protector
+#include <unistd.h>
+#include <sys/types.h>
+#include <pwd.h>
+#include <grp.h>
+#include <stdlib.h>
+#include <string.h>
+
+static struct passwd mygetpwuid_r(int uid, char *buf, size_t buflen, int *found, int *perr) {
+ struct passwd pwd;
+ struct passwd *result;
+ memset (&pwd, 0, sizeof(pwd));
+ *perr = getpwuid_r(uid, &pwd, buf, buflen, &result);
+ *found = result != NULL;
+ return pwd;
+}
+
+static struct passwd mygetpwnam_r(const char *name, char *buf, size_t buflen, int *found, int *perr) {
+ struct passwd pwd;
+ struct passwd *result;
+ memset(&pwd, 0, sizeof(pwd));
+ *perr = getpwnam_r(name, &pwd, buf, buflen, &result);
+ *found = result != NULL;
+ return pwd;
+}
+
+static struct group mygetgrgid_r(int gid, char *buf, size_t buflen, int *found, int *perr) {
+ struct group grp;
+ struct group *result;
+ memset(&grp, 0, sizeof(grp));
+ *perr = getgrgid_r(gid, &grp, buf, buflen, &result);
+ *found = result != NULL;
+ return grp;
+}
+
+static struct group mygetgrnam_r(const char *name, char *buf, size_t buflen, int *found, int *perr) {
+ struct group grp;
+ struct group *result;
+ memset(&grp, 0, sizeof(grp));
+ *perr = getgrnam_r(name, &grp, buf, buflen, &result);
+ *found = result != NULL;
+ return grp;
+}
+*/
+import "C"
+
+type _C_char = C.char
+type _C_int = C.int
+type _C_gid_t = C.gid_t
+type _C_uid_t = C.uid_t
+type _C_size_t = C.size_t
+type _C_struct_group = C.struct_group
+type _C_struct_passwd = C.struct_passwd
+type _C_long = C.long
+
+func _C_pw_uid(p *_C_struct_passwd) _C_uid_t { return p.pw_uid }
+func _C_pw_uidp(p *_C_struct_passwd) *_C_uid_t { return &p.pw_uid }
+func _C_pw_gid(p *_C_struct_passwd) _C_gid_t { return p.pw_gid }
+func _C_pw_gidp(p *_C_struct_passwd) *_C_gid_t { return &p.pw_gid }
+func _C_pw_name(p *_C_struct_passwd) *_C_char { return p.pw_name }
+func _C_pw_gecos(p *_C_struct_passwd) *_C_char { return p.pw_gecos }
+func _C_pw_dir(p *_C_struct_passwd) *_C_char { return p.pw_dir }
+
+func _C_gr_gid(g *_C_struct_group) _C_gid_t { return g.gr_gid }
+func _C_gr_name(g *_C_struct_group) *_C_char { return g.gr_name }
+
+func _C_GoString(p *_C_char) string { return C.GoString(p) }
+
+func _C_getpwnam_r(name *_C_char, buf *_C_char, size _C_size_t) (pwd _C_struct_passwd, found bool, errno syscall.Errno) {
+ var f, e _C_int
+ pwd = C.mygetpwnam_r(name, buf, size, &f, &e)
+ return pwd, f != 0, syscall.Errno(e)
+}
+
+func _C_getpwuid_r(uid _C_uid_t, buf *_C_char, size _C_size_t) (pwd _C_struct_passwd, found bool, errno syscall.Errno) {
+ var f, e _C_int
+ pwd = C.mygetpwuid_r(_C_int(uid), buf, size, &f, &e)
+ return pwd, f != 0, syscall.Errno(e)
+}
+
+func _C_getgrnam_r(name *_C_char, buf *_C_char, size _C_size_t) (grp _C_struct_group, found bool, errno syscall.Errno) {
+ var f, e _C_int
+ grp = C.mygetgrnam_r(name, buf, size, &f, &e)
+ return grp, f != 0, syscall.Errno(e)
+}
+
+func _C_getgrgid_r(gid _C_gid_t, buf *_C_char, size _C_size_t) (grp _C_struct_group, found bool, errno syscall.Errno) {
+ var f, e _C_int
+ grp = C.mygetgrgid_r(_C_int(gid), buf, size, &f, &e)
+ return grp, f != 0, syscall.Errno(e)
+}
+
+const (
+ _C__SC_GETPW_R_SIZE_MAX = C._SC_GETPW_R_SIZE_MAX
+ _C__SC_GETGR_R_SIZE_MAX = C._SC_GETGR_R_SIZE_MAX
+)
+
+func _C_sysconf(key _C_int) _C_long { return C.sysconf(key) }
diff --git a/contrib/go/_std_1.22/src/os/user/cgo_lookup_syscall.go b/contrib/go/_std_1.22/src/os/user/cgo_lookup_syscall.go
new file mode 100644
index 0000000000..321df652be
--- /dev/null
+++ b/contrib/go/_std_1.22/src/os/user/cgo_lookup_syscall.go
@@ -0,0 +1,65 @@
+// Copyright 2011 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+//go:build !osusergo && darwin
+
+package user
+
+import (
+ "internal/syscall/unix"
+ "syscall"
+)
+
+type _C_char = byte
+type _C_int = int32
+type _C_gid_t = uint32
+type _C_uid_t = uint32
+type _C_size_t = uintptr
+type _C_struct_group = unix.Group
+type _C_struct_passwd = unix.Passwd
+type _C_long = int64
+
+func _C_pw_uid(p *_C_struct_passwd) _C_uid_t { return p.Uid }
+func _C_pw_uidp(p *_C_struct_passwd) *_C_uid_t { return &p.Uid }
+func _C_pw_gid(p *_C_struct_passwd) _C_gid_t { return p.Gid }
+func _C_pw_gidp(p *_C_struct_passwd) *_C_gid_t { return &p.Gid }
+func _C_pw_name(p *_C_struct_passwd) *_C_char { return p.Name }
+func _C_pw_gecos(p *_C_struct_passwd) *_C_char { return p.Gecos }
+func _C_pw_dir(p *_C_struct_passwd) *_C_char { return p.Dir }
+
+func _C_gr_gid(g *_C_struct_group) _C_gid_t { return g.Gid }
+func _C_gr_name(g *_C_struct_group) *_C_char { return g.Name }
+
+func _C_GoString(p *_C_char) string { return unix.GoString(p) }
+
+func _C_getpwnam_r(name *_C_char, buf *_C_char, size _C_size_t) (pwd _C_struct_passwd, found bool, errno syscall.Errno) {
+ var result *_C_struct_passwd
+ errno = unix.Getpwnam(name, &pwd, buf, size, &result)
+ return pwd, result != nil, errno
+}
+
+func _C_getpwuid_r(uid _C_uid_t, buf *_C_char, size _C_size_t) (pwd _C_struct_passwd, found bool, errno syscall.Errno) {
+ var result *_C_struct_passwd
+ errno = unix.Getpwuid(uid, &pwd, buf, size, &result)
+ return pwd, result != nil, errno
+}
+
+func _C_getgrnam_r(name *_C_char, buf *_C_char, size _C_size_t) (grp _C_struct_group, found bool, errno syscall.Errno) {
+ var result *_C_struct_group
+ errno = unix.Getgrnam(name, &grp, buf, size, &result)
+ return grp, result != nil, errno
+}
+
+func _C_getgrgid_r(gid _C_gid_t, buf *_C_char, size _C_size_t) (grp _C_struct_group, found bool, errno syscall.Errno) {
+ var result *_C_struct_group
+ errno = unix.Getgrgid(gid, &grp, buf, size, &result)
+ return grp, result != nil, errno
+}
+
+const (
+ _C__SC_GETPW_R_SIZE_MAX = unix.SC_GETPW_R_SIZE_MAX
+ _C__SC_GETGR_R_SIZE_MAX = unix.SC_GETGR_R_SIZE_MAX
+)
+
+func _C_sysconf(key _C_int) _C_long { return unix.Sysconf(key) }
diff --git a/contrib/go/_std_1.22/src/os/user/cgo_lookup_unix.go b/contrib/go/_std_1.22/src/os/user/cgo_lookup_unix.go
new file mode 100644
index 0000000000..402429ba4a
--- /dev/null
+++ b/contrib/go/_std_1.22/src/os/user/cgo_lookup_unix.go
@@ -0,0 +1,200 @@
+// Copyright 2011 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+//go:build (cgo || darwin) && !osusergo && unix && !android
+
+package user
+
+import (
+ "fmt"
+ "runtime"
+ "strconv"
+ "strings"
+ "syscall"
+ "unsafe"
+)
+
+func current() (*User, error) {
+ return lookupUnixUid(syscall.Getuid())
+}
+
+func lookupUser(username string) (*User, error) {
+ var pwd _C_struct_passwd
+ var found bool
+ nameC := make([]byte, len(username)+1)
+ copy(nameC, username)
+
+ err := retryWithBuffer(userBuffer, func(buf []byte) syscall.Errno {
+ var errno syscall.Errno
+ pwd, found, errno = _C_getpwnam_r((*_C_char)(unsafe.Pointer(&nameC[0])),
+ (*_C_char)(unsafe.Pointer(&buf[0])), _C_size_t(len(buf)))
+ return errno
+ })
+ if err != nil {
+ return nil, fmt.Errorf("user: lookup username %s: %v", username, err)
+ }
+ if !found {
+ return nil, UnknownUserError(username)
+ }
+ return buildUser(&pwd), err
+}
+
+func lookupUserId(uid string) (*User, error) {
+ i, e := strconv.Atoi(uid)
+ if e != nil {
+ return nil, e
+ }
+ return lookupUnixUid(i)
+}
+
+func lookupUnixUid(uid int) (*User, error) {
+ var pwd _C_struct_passwd
+ var found bool
+
+ err := retryWithBuffer(userBuffer, func(buf []byte) syscall.Errno {
+ var errno syscall.Errno
+ pwd, found, errno = _C_getpwuid_r(_C_uid_t(uid),
+ (*_C_char)(unsafe.Pointer(&buf[0])), _C_size_t(len(buf)))
+ return errno
+ })
+ if err != nil {
+ return nil, fmt.Errorf("user: lookup userid %d: %v", uid, err)
+ }
+ if !found {
+ return nil, UnknownUserIdError(uid)
+ }
+ return buildUser(&pwd), nil
+}
+
+func buildUser(pwd *_C_struct_passwd) *User {
+ u := &User{
+ Uid: strconv.FormatUint(uint64(_C_pw_uid(pwd)), 10),
+ Gid: strconv.FormatUint(uint64(_C_pw_gid(pwd)), 10),
+ Username: _C_GoString(_C_pw_name(pwd)),
+ Name: _C_GoString(_C_pw_gecos(pwd)),
+ HomeDir: _C_GoString(_C_pw_dir(pwd)),
+ }
+ // The pw_gecos field isn't quite standardized. Some docs
+ // say: "It is expected to be a comma separated list of
+ // personal data where the first item is the full name of the
+ // user."
+ u.Name, _, _ = strings.Cut(u.Name, ",")
+ return u
+}
+
+func lookupGroup(groupname string) (*Group, error) {
+ var grp _C_struct_group
+ var found bool
+
+ cname := make([]byte, len(groupname)+1)
+ copy(cname, groupname)
+
+ err := retryWithBuffer(groupBuffer, func(buf []byte) syscall.Errno {
+ var errno syscall.Errno
+ grp, found, errno = _C_getgrnam_r((*_C_char)(unsafe.Pointer(&cname[0])),
+ (*_C_char)(unsafe.Pointer(&buf[0])), _C_size_t(len(buf)))
+ return errno
+ })
+ if err != nil {
+ return nil, fmt.Errorf("user: lookup groupname %s: %v", groupname, err)
+ }
+ if !found {
+ return nil, UnknownGroupError(groupname)
+ }
+ return buildGroup(&grp), nil
+}
+
+func lookupGroupId(gid string) (*Group, error) {
+ i, e := strconv.Atoi(gid)
+ if e != nil {
+ return nil, e
+ }
+ return lookupUnixGid(i)
+}
+
+func lookupUnixGid(gid int) (*Group, error) {
+ var grp _C_struct_group
+ var found bool
+
+ err := retryWithBuffer(groupBuffer, func(buf []byte) syscall.Errno {
+ var errno syscall.Errno
+ grp, found, errno = _C_getgrgid_r(_C_gid_t(gid),
+ (*_C_char)(unsafe.Pointer(&buf[0])), _C_size_t(len(buf)))
+ return syscall.Errno(errno)
+ })
+ if err != nil {
+ return nil, fmt.Errorf("user: lookup groupid %d: %v", gid, err)
+ }
+ if !found {
+ return nil, UnknownGroupIdError(strconv.Itoa(gid))
+ }
+ return buildGroup(&grp), nil
+}
+
+func buildGroup(grp *_C_struct_group) *Group {
+ g := &Group{
+ Gid: strconv.Itoa(int(_C_gr_gid(grp))),
+ Name: _C_GoString(_C_gr_name(grp)),
+ }
+ return g
+}
+
+type bufferKind _C_int
+
+var (
+ userBuffer = bufferKind(_C__SC_GETPW_R_SIZE_MAX)
+ groupBuffer = bufferKind(_C__SC_GETGR_R_SIZE_MAX)
+)
+
+func (k bufferKind) initialSize() _C_size_t {
+ sz := _C_sysconf(_C_int(k))
+ if sz == -1 {
+ // DragonFly and FreeBSD do not have _SC_GETPW_R_SIZE_MAX.
+ // Additionally, not all Linux systems have it, either. For
+ // example, the musl libc returns -1.
+ return 1024
+ }
+ if !isSizeReasonable(int64(sz)) {
+ // Truncate. If this truly isn't enough, retryWithBuffer will error on the first run.
+ return maxBufferSize
+ }
+ return _C_size_t(sz)
+}
+
+// retryWithBuffer repeatedly calls f(), increasing the size of the
+// buffer each time, until f succeeds, fails with a non-ERANGE error,
+// or the buffer exceeds a reasonable limit.
+func retryWithBuffer(kind bufferKind, f func([]byte) syscall.Errno) error {
+ buf := make([]byte, kind.initialSize())
+ for {
+ errno := f(buf)
+ if errno == 0 {
+ return nil
+ } else if runtime.GOOS == "aix" && errno+1 == 0 {
+ // On AIX getpwuid_r appears to return -1,
+ // not ERANGE, on buffer overflow.
+ } else if errno != syscall.ERANGE {
+ return errno
+ }
+ newSize := len(buf) * 2
+ if !isSizeReasonable(int64(newSize)) {
+ return fmt.Errorf("internal buffer exceeds %d bytes", maxBufferSize)
+ }
+ buf = make([]byte, newSize)
+ }
+}
+
+const maxBufferSize = 1 << 20
+
+func isSizeReasonable(sz int64) bool {
+ return sz > 0 && sz <= maxBufferSize
+}
+
+// Because we can't use cgo in tests:
+func structPasswdForNegativeTest() _C_struct_passwd {
+ sp := _C_struct_passwd{}
+ *_C_pw_uidp(&sp) = 1<<32 - 2
+ *_C_pw_gidp(&sp) = 1<<32 - 3
+ return sp
+}
diff --git a/contrib/go/_std_1.22/src/os/user/getgrouplist_syscall.go b/contrib/go/_std_1.22/src/os/user/getgrouplist_syscall.go
new file mode 100644
index 0000000000..41b64fca93
--- /dev/null
+++ b/contrib/go/_std_1.22/src/os/user/getgrouplist_syscall.go
@@ -0,0 +1,19 @@
+// Copyright 2016 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+//go:build !osusergo && darwin
+
+package user
+
+import (
+ "internal/syscall/unix"
+)
+
+func getGroupList(name *_C_char, userGID _C_gid_t, gids *_C_gid_t, n *_C_int) _C_int {
+ err := unix.Getgrouplist(name, userGID, gids, n)
+ if err != nil {
+ return -1
+ }
+ return 0
+}
diff --git a/contrib/go/_std_1.22/src/os/user/getgrouplist_unix.go b/contrib/go/_std_1.22/src/os/user/getgrouplist_unix.go
new file mode 100644
index 0000000000..fb482d35ba
--- /dev/null
+++ b/contrib/go/_std_1.22/src/os/user/getgrouplist_unix.go
@@ -0,0 +1,22 @@
+// Copyright 2016 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+//go:build cgo && !osusergo && (dragonfly || freebsd || (!android && linux) || netbsd || openbsd || (solaris && !illumos))
+
+package user
+
+/*
+#include <unistd.h>
+#include <sys/types.h>
+#include <grp.h>
+
+static int mygetgrouplist(const char* user, gid_t group, gid_t* groups, int* ngroups) {
+ return getgrouplist(user, group, groups, ngroups);
+}
+*/
+import "C"
+
+func getGroupList(name *_C_char, userGID _C_gid_t, gids *_C_gid_t, n *_C_int) _C_int {
+ return C.mygetgrouplist(name, userGID, gids, n)
+}
diff --git a/contrib/go/_std_1.22/src/os/user/lookup.go b/contrib/go/_std_1.22/src/os/user/lookup.go
new file mode 100644
index 0000000000..ed33d0c7cd
--- /dev/null
+++ b/contrib/go/_std_1.22/src/os/user/lookup.go
@@ -0,0 +1,70 @@
+// Copyright 2011 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package user
+
+import "sync"
+
+const (
+ userFile = "/etc/passwd"
+ groupFile = "/etc/group"
+)
+
+var colon = []byte{':'}
+
+// Current returns the current user.
+//
+// The first call will cache the current user information.
+// Subsequent calls will return the cached value and will not reflect
+// changes to the current user.
+func Current() (*User, error) {
+ cache.Do(func() { cache.u, cache.err = current() })
+ if cache.err != nil {
+ return nil, cache.err
+ }
+ u := *cache.u // copy
+ return &u, nil
+}
+
+// cache of the current user
+var cache struct {
+ sync.Once
+ u *User
+ err error
+}
+
+// Lookup looks up a user by username. If the user cannot be found, the
+// returned error is of type UnknownUserError.
+func Lookup(username string) (*User, error) {
+ if u, err := Current(); err == nil && u.Username == username {
+ return u, err
+ }
+ return lookupUser(username)
+}
+
+// LookupId looks up a user by userid. If the user cannot be found, the
+// returned error is of type UnknownUserIdError.
+func LookupId(uid string) (*User, error) {
+ if u, err := Current(); err == nil && u.Uid == uid {
+ return u, err
+ }
+ return lookupUserId(uid)
+}
+
+// LookupGroup looks up a group by name. If the group cannot be found, the
+// returned error is of type UnknownGroupError.
+func LookupGroup(name string) (*Group, error) {
+ return lookupGroup(name)
+}
+
+// LookupGroupId looks up a group by groupid. If the group cannot be found, the
+// returned error is of type UnknownGroupIdError.
+func LookupGroupId(gid string) (*Group, error) {
+ return lookupGroupId(gid)
+}
+
+// GroupIds returns the list of group IDs that the user is a member of.
+func (u *User) GroupIds() ([]string, error) {
+ return listGroups(u)
+}
diff --git a/contrib/go/_std_1.22/src/os/user/lookup_windows.go b/contrib/go/_std_1.22/src/os/user/lookup_windows.go
new file mode 100644
index 0000000000..a48fc89720
--- /dev/null
+++ b/contrib/go/_std_1.22/src/os/user/lookup_windows.go
@@ -0,0 +1,392 @@
+// Copyright 2012 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package user
+
+import (
+ "fmt"
+ "internal/syscall/windows"
+ "internal/syscall/windows/registry"
+ "syscall"
+ "unsafe"
+)
+
+func isDomainJoined() (bool, error) {
+ var domain *uint16
+ var status uint32
+ err := syscall.NetGetJoinInformation(nil, &domain, &status)
+ if err != nil {
+ return false, err
+ }
+ syscall.NetApiBufferFree((*byte)(unsafe.Pointer(domain)))
+ return status == syscall.NetSetupDomainName, nil
+}
+
+func lookupFullNameDomain(domainAndUser string) (string, error) {
+ return syscall.TranslateAccountName(domainAndUser,
+ syscall.NameSamCompatible, syscall.NameDisplay, 50)
+}
+
+func lookupFullNameServer(servername, username string) (string, error) {
+ s, e := syscall.UTF16PtrFromString(servername)
+ if e != nil {
+ return "", e
+ }
+ u, e := syscall.UTF16PtrFromString(username)
+ if e != nil {
+ return "", e
+ }
+ var p *byte
+ e = syscall.NetUserGetInfo(s, u, 10, &p)
+ if e != nil {
+ return "", e
+ }
+ defer syscall.NetApiBufferFree(p)
+ i := (*syscall.UserInfo10)(unsafe.Pointer(p))
+ return windows.UTF16PtrToString(i.FullName), nil
+}
+
+func lookupFullName(domain, username, domainAndUser string) (string, error) {
+ joined, err := isDomainJoined()
+ if err == nil && joined {
+ name, err := lookupFullNameDomain(domainAndUser)
+ if err == nil {
+ return name, nil
+ }
+ }
+ name, err := lookupFullNameServer(domain, username)
+ if err == nil {
+ return name, nil
+ }
+ // domain worked neither as a domain nor as a server
+ // could be domain server unavailable
+ // pretend username is fullname
+ return username, nil
+}
+
+// getProfilesDirectory retrieves the path to the root directory
+// where user profiles are stored.
+func getProfilesDirectory() (string, error) {
+ n := uint32(100)
+ for {
+ b := make([]uint16, n)
+ e := windows.GetProfilesDirectory(&b[0], &n)
+ if e == nil {
+ return syscall.UTF16ToString(b), nil
+ }
+ if e != syscall.ERROR_INSUFFICIENT_BUFFER {
+ return "", e
+ }
+ if n <= uint32(len(b)) {
+ return "", e
+ }
+ }
+}
+
+// lookupUsernameAndDomain obtains the username and domain for usid.
+func lookupUsernameAndDomain(usid *syscall.SID) (username, domain string, e error) {
+ username, domain, t, e := usid.LookupAccount("")
+ if e != nil {
+ return "", "", e
+ }
+ if t != syscall.SidTypeUser {
+ return "", "", fmt.Errorf("user: should be user account type, not %d", t)
+ }
+ return username, domain, nil
+}
+
+// findHomeDirInRegistry finds the user home path based on the uid.
+func findHomeDirInRegistry(uid string) (dir string, e error) {
+ k, e := registry.OpenKey(registry.LOCAL_MACHINE, `SOFTWARE\Microsoft\Windows NT\CurrentVersion\ProfileList\`+uid, registry.QUERY_VALUE)
+ if e != nil {
+ return "", e
+ }
+ defer k.Close()
+ dir, _, e = k.GetStringValue("ProfileImagePath")
+ if e != nil {
+ return "", e
+ }
+ return dir, nil
+}
+
+// lookupGroupName accepts the name of a group and retrieves the group SID.
+func lookupGroupName(groupname string) (string, error) {
+ sid, _, t, e := syscall.LookupSID("", groupname)
+ if e != nil {
+ return "", e
+ }
+ // https://learn.microsoft.com/en-us/openspecs/windows_protocols/ms-samr/7b2aeb27-92fc-41f6-8437-deb65d950921#gt_0387e636-5654-4910-9519-1f8326cf5ec0
+ // SidTypeAlias should also be treated as a group type next to SidTypeGroup
+ // and SidTypeWellKnownGroup:
+ // "alias object -> resource group: A group object..."
+ //
+ // Tests show that "Administrators" can be considered of type SidTypeAlias.
+ if t != syscall.SidTypeGroup && t != syscall.SidTypeWellKnownGroup && t != syscall.SidTypeAlias {
+ return "", fmt.Errorf("lookupGroupName: should be group account type, not %d", t)
+ }
+ return sid.String()
+}
+
+// listGroupsForUsernameAndDomain accepts username and domain and retrieves
+// a SID list of the local groups where this user is a member.
+func listGroupsForUsernameAndDomain(username, domain string) ([]string, error) {
+ // Check if both the domain name and user should be used.
+ var query string
+ joined, err := isDomainJoined()
+ if err == nil && joined && len(domain) != 0 {
+ query = domain + `\` + username
+ } else {
+ query = username
+ }
+ q, err := syscall.UTF16PtrFromString(query)
+ if err != nil {
+ return nil, err
+ }
+ var p0 *byte
+ var entriesRead, totalEntries uint32
+ // https://learn.microsoft.com/en-us/windows/win32/api/lmaccess/nf-lmaccess-netusergetlocalgroups
+ // NetUserGetLocalGroups() would return a list of LocalGroupUserInfo0
+ // elements which hold the names of local groups where the user participates.
+ // The list does not follow any sorting order.
+ //
+ // If no groups can be found for this user, NetUserGetLocalGroups() should
+ // always return the SID of a single group called "None", which
+ // also happens to be the primary group for the local user.
+ err = windows.NetUserGetLocalGroups(nil, q, 0, windows.LG_INCLUDE_INDIRECT, &p0, windows.MAX_PREFERRED_LENGTH, &entriesRead, &totalEntries)
+ if err != nil {
+ return nil, err
+ }
+ defer syscall.NetApiBufferFree(p0)
+ if entriesRead == 0 {
+ return nil, fmt.Errorf("listGroupsForUsernameAndDomain: NetUserGetLocalGroups() returned an empty list for domain: %s, username: %s", domain, username)
+ }
+ entries := (*[1024]windows.LocalGroupUserInfo0)(unsafe.Pointer(p0))[:entriesRead:entriesRead]
+ var sids []string
+ for _, entry := range entries {
+ if entry.Name == nil {
+ continue
+ }
+ sid, err := lookupGroupName(windows.UTF16PtrToString(entry.Name))
+ if err != nil {
+ return nil, err
+ }
+ sids = append(sids, sid)
+ }
+ return sids, nil
+}
+
+func newUser(uid, gid, dir, username, domain string) (*User, error) {
+ domainAndUser := domain + `\` + username
+ name, e := lookupFullName(domain, username, domainAndUser)
+ if e != nil {
+ return nil, e
+ }
+ u := &User{
+ Uid: uid,
+ Gid: gid,
+ Username: domainAndUser,
+ Name: name,
+ HomeDir: dir,
+ }
+ return u, nil
+}
+
+var (
+ // unused variables (in this implementation)
+ // modified during test to exercise code paths in the cgo implementation.
+ userBuffer = 0
+ groupBuffer = 0
+)
+
+func current() (*User, error) {
+ t, e := syscall.OpenCurrentProcessToken()
+ if e != nil {
+ return nil, e
+ }
+ defer t.Close()
+ u, e := t.GetTokenUser()
+ if e != nil {
+ return nil, e
+ }
+ pg, e := t.GetTokenPrimaryGroup()
+ if e != nil {
+ return nil, e
+ }
+ uid, e := u.User.Sid.String()
+ if e != nil {
+ return nil, e
+ }
+ gid, e := pg.PrimaryGroup.String()
+ if e != nil {
+ return nil, e
+ }
+ dir, e := t.GetUserProfileDirectory()
+ if e != nil {
+ return nil, e
+ }
+ username, domain, e := lookupUsernameAndDomain(u.User.Sid)
+ if e != nil {
+ return nil, e
+ }
+ return newUser(uid, gid, dir, username, domain)
+}
+
+// lookupUserPrimaryGroup obtains the primary group SID for a user using this method:
+// https://support.microsoft.com/en-us/help/297951/how-to-use-the-primarygroupid-attribute-to-find-the-primary-group-for
+// The method follows this formula: domainRID + "-" + primaryGroupRID
+func lookupUserPrimaryGroup(username, domain string) (string, error) {
+ // get the domain RID
+ sid, _, t, e := syscall.LookupSID("", domain)
+ if e != nil {
+ return "", e
+ }
+ if t != syscall.SidTypeDomain {
+ return "", fmt.Errorf("lookupUserPrimaryGroup: should be domain account type, not %d", t)
+ }
+ domainRID, e := sid.String()
+ if e != nil {
+ return "", e
+ }
+ // If the user has joined a domain use the RID of the default primary group
+ // called "Domain Users":
+ // https://support.microsoft.com/en-us/help/243330/well-known-security-identifiers-in-windows-operating-systems
+ // SID: S-1-5-21domain-513
+ //
+ // The correct way to obtain the primary group of a domain user is
+ // probing the user primaryGroupID attribute in the server Active Directory:
+ // https://learn.microsoft.com/en-us/windows/win32/adschema/a-primarygroupid
+ //
+ // Note that the primary group of domain users should not be modified
+ // on Windows for performance reasons, even if it's possible to do that.
+ // The .NET Developer's Guide to Directory Services Programming - Page 409
+ // https://books.google.bg/books?id=kGApqjobEfsC&lpg=PA410&ots=p7oo-eOQL7&dq=primary%20group%20RID&hl=bg&pg=PA409#v=onepage&q&f=false
+ joined, err := isDomainJoined()
+ if err == nil && joined {
+ return domainRID + "-513", nil
+ }
+ // For non-domain users call NetUserGetInfo() with level 4, which
+ // in this case would not have any network overhead.
+ // The primary group should not change from RID 513 here either
+ // but the group will be called "None" instead:
+ // https://www.adampalmer.me/iodigitalsec/2013/08/10/windows-null-session-enumeration/
+ // "Group 'None' (RID: 513)"
+ u, e := syscall.UTF16PtrFromString(username)
+ if e != nil {
+ return "", e
+ }
+ d, e := syscall.UTF16PtrFromString(domain)
+ if e != nil {
+ return "", e
+ }
+ var p *byte
+ e = syscall.NetUserGetInfo(d, u, 4, &p)
+ if e != nil {
+ return "", e
+ }
+ defer syscall.NetApiBufferFree(p)
+ i := (*windows.UserInfo4)(unsafe.Pointer(p))
+ return fmt.Sprintf("%s-%d", domainRID, i.PrimaryGroupID), nil
+}
+
+func newUserFromSid(usid *syscall.SID) (*User, error) {
+ username, domain, e := lookupUsernameAndDomain(usid)
+ if e != nil {
+ return nil, e
+ }
+ gid, e := lookupUserPrimaryGroup(username, domain)
+ if e != nil {
+ return nil, e
+ }
+ uid, e := usid.String()
+ if e != nil {
+ return nil, e
+ }
+ // If this user has logged in at least once their home path should be stored
+ // in the registry under the specified SID. References:
+ // https://social.technet.microsoft.com/wiki/contents/articles/13895.how-to-remove-a-corrupted-user-profile-from-the-registry.aspx
+ // https://support.asperasoft.com/hc/en-us/articles/216127438-How-to-delete-Windows-user-profiles
+ //
+ // The registry is the most reliable way to find the home path as the user
+ // might have decided to move it outside of the default location,
+ // (e.g. C:\users). Reference:
+ // https://answers.microsoft.com/en-us/windows/forum/windows_7-security/how-do-i-set-a-home-directory-outside-cusers-for-a/aed68262-1bf4-4a4d-93dc-7495193a440f
+ dir, e := findHomeDirInRegistry(uid)
+ if e != nil {
+ // If the home path does not exist in the registry, the user might
+ // have not logged in yet; fall back to using getProfilesDirectory().
+ // Find the username based on a SID and append that to the result of
+ // getProfilesDirectory(). The domain is not relevant here.
+ dir, e = getProfilesDirectory()
+ if e != nil {
+ return nil, e
+ }
+ dir += `\` + username
+ }
+ return newUser(uid, gid, dir, username, domain)
+}
+
+func lookupUser(username string) (*User, error) {
+ sid, _, t, e := syscall.LookupSID("", username)
+ if e != nil {
+ return nil, e
+ }
+ if t != syscall.SidTypeUser {
+ return nil, fmt.Errorf("user: should be user account type, not %d", t)
+ }
+ return newUserFromSid(sid)
+}
+
+func lookupUserId(uid string) (*User, error) {
+ sid, e := syscall.StringToSid(uid)
+ if e != nil {
+ return nil, e
+ }
+ return newUserFromSid(sid)
+}
+
+func lookupGroup(groupname string) (*Group, error) {
+ sid, err := lookupGroupName(groupname)
+ if err != nil {
+ return nil, err
+ }
+ return &Group{Name: groupname, Gid: sid}, nil
+}
+
+func lookupGroupId(gid string) (*Group, error) {
+ sid, err := syscall.StringToSid(gid)
+ if err != nil {
+ return nil, err
+ }
+ groupname, _, t, err := sid.LookupAccount("")
+ if err != nil {
+ return nil, err
+ }
+ if t != syscall.SidTypeGroup && t != syscall.SidTypeWellKnownGroup && t != syscall.SidTypeAlias {
+ return nil, fmt.Errorf("lookupGroupId: should be group account type, not %d", t)
+ }
+ return &Group{Name: groupname, Gid: gid}, nil
+}
+
+func listGroups(user *User) ([]string, error) {
+ sid, err := syscall.StringToSid(user.Uid)
+ if err != nil {
+ return nil, err
+ }
+ username, domain, err := lookupUsernameAndDomain(sid)
+ if err != nil {
+ return nil, err
+ }
+ sids, err := listGroupsForUsernameAndDomain(username, domain)
+ if err != nil {
+ return nil, err
+ }
+ // Add the primary group of the user to the list if it is not already there.
+ // This is done only to comply with the POSIX concept of a primary group.
+ for _, sid := range sids {
+ if sid == user.Gid {
+ return sids, nil
+ }
+ }
+ return append(sids, user.Gid), nil
+}
diff --git a/contrib/go/_std_1.22/src/os/user/user.go b/contrib/go/_std_1.22/src/os/user/user.go
new file mode 100644
index 0000000000..0307d2ad6a
--- /dev/null
+++ b/contrib/go/_std_1.22/src/os/user/user.go
@@ -0,0 +1,95 @@
+// Copyright 2011 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+/*
+Package user allows user account lookups by name or id.
+
+For most Unix systems, this package has two internal implementations of
+resolving user and group ids to names, and listing supplementary group IDs.
+One is written in pure Go and parses /etc/passwd and /etc/group. The other
+is cgo-based and relies on the standard C library (libc) routines such as
+getpwuid_r, getgrnam_r, and getgrouplist.
+
+When cgo is available, and the required routines are implemented in libc
+for a particular platform, cgo-based (libc-backed) code is used.
+This can be overridden by using osusergo build tag, which enforces
+the pure Go implementation.
+*/
+package user
+
+import (
+ "strconv"
+)
+
+// These may be set to false in init() for a particular platform and/or
+// build flags to let the tests know to skip tests of some features.
+var (
+ userImplemented = true
+ groupImplemented = true
+ groupListImplemented = true
+)
+
+// User represents a user account.
+type User struct {
+ // Uid is the user ID.
+ // On POSIX systems, this is a decimal number representing the uid.
+ // On Windows, this is a security identifier (SID) in a string format.
+ // On Plan 9, this is the contents of /dev/user.
+ Uid string
+ // Gid is the primary group ID.
+ // On POSIX systems, this is a decimal number representing the gid.
+ // On Windows, this is a SID in a string format.
+ // On Plan 9, this is the contents of /dev/user.
+ Gid string
+ // Username is the login name.
+ Username string
+ // Name is the user's real or display name.
+ // It might be blank.
+ // On POSIX systems, this is the first (or only) entry in the GECOS field
+ // list.
+ // On Windows, this is the user's display name.
+ // On Plan 9, this is the contents of /dev/user.
+ Name string
+ // HomeDir is the path to the user's home directory (if they have one).
+ HomeDir string
+}
+
+// Group represents a grouping of users.
+//
+// On POSIX systems Gid contains a decimal number representing the group ID.
+type Group struct {
+ Gid string // group ID
+ Name string // group name
+}
+
+// UnknownUserIdError is returned by LookupId when a user cannot be found.
+type UnknownUserIdError int
+
+func (e UnknownUserIdError) Error() string {
+ return "user: unknown userid " + strconv.Itoa(int(e))
+}
+
+// UnknownUserError is returned by Lookup when
+// a user cannot be found.
+type UnknownUserError string
+
+func (e UnknownUserError) Error() string {
+ return "user: unknown user " + string(e)
+}
+
+// UnknownGroupIdError is returned by LookupGroupId when
+// a group cannot be found.
+type UnknownGroupIdError string
+
+func (e UnknownGroupIdError) Error() string {
+ return "group: unknown groupid " + string(e)
+}
+
+// UnknownGroupError is returned by LookupGroup when
+// a group cannot be found.
+type UnknownGroupError string
+
+func (e UnknownGroupError) Error() string {
+ return "group: unknown group " + string(e)
+}
diff --git a/contrib/go/_std_1.22/src/os/user/ya.make b/contrib/go/_std_1.22/src/os/user/ya.make
new file mode 100644
index 0000000000..3bf6d0640d
--- /dev/null
+++ b/contrib/go/_std_1.22/src/os/user/ya.make
@@ -0,0 +1,40 @@
+GO_LIBRARY()
+IF (OS_DARWIN AND ARCH_ARM64 AND RACE AND CGO_ENABLED OR OS_DARWIN AND ARCH_ARM64 AND RACE AND NOT CGO_ENABLED OR OS_DARWIN AND ARCH_ARM64 AND NOT RACE AND CGO_ENABLED OR OS_DARWIN AND ARCH_ARM64 AND NOT RACE AND NOT CGO_ENABLED OR OS_DARWIN AND ARCH_X86_64 AND RACE AND CGO_ENABLED OR OS_DARWIN AND ARCH_X86_64 AND RACE AND NOT CGO_ENABLED OR OS_DARWIN AND ARCH_X86_64 AND NOT RACE AND CGO_ENABLED OR OS_DARWIN AND ARCH_X86_64 AND NOT RACE AND NOT CGO_ENABLED)
+ SRCS(
+ cgo_listgroups_unix.go
+ cgo_lookup_syscall.go
+ cgo_lookup_unix.go
+ getgrouplist_syscall.go
+ lookup.go
+ user.go
+ )
+ELSEIF (OS_LINUX AND ARCH_AARCH64 AND RACE AND CGO_ENABLED OR OS_LINUX AND ARCH_AARCH64 AND NOT RACE AND CGO_ENABLED OR OS_LINUX AND ARCH_X86_64 AND RACE AND CGO_ENABLED OR OS_LINUX AND ARCH_X86_64 AND NOT RACE AND CGO_ENABLED)
+ SRCS(
+ cgo_listgroups_unix.go
+ cgo_lookup_unix.go
+ lookup.go
+ user.go
+ )
+
+IF (CGO_ENABLED)
+ CGO_SRCS(
+ cgo_lookup_cgo.go
+ getgrouplist_unix.go
+ )
+ENDIF()
+ELSEIF (OS_LINUX AND ARCH_AARCH64 AND RACE AND NOT CGO_ENABLED OR OS_LINUX AND ARCH_AARCH64 AND NOT RACE AND NOT CGO_ENABLED OR OS_LINUX AND ARCH_X86_64 AND RACE AND NOT CGO_ENABLED OR OS_LINUX AND ARCH_X86_64 AND NOT RACE AND NOT CGO_ENABLED)
+ SRCS(
+ listgroups_unix.go
+ lookup.go
+ lookup_stubs.go
+ lookup_unix.go
+ user.go
+ )
+ELSEIF (OS_WINDOWS AND ARCH_X86_64 AND RACE AND CGO_ENABLED OR OS_WINDOWS AND ARCH_X86_64 AND RACE AND NOT CGO_ENABLED OR OS_WINDOWS AND ARCH_X86_64 AND NOT RACE AND CGO_ENABLED OR OS_WINDOWS AND ARCH_X86_64 AND NOT RACE AND NOT CGO_ENABLED)
+ SRCS(
+ lookup.go
+ lookup_windows.go
+ user.go
+ )
+ENDIF()
+END()