2012-03-27 23:13:14 +00:00
|
|
|
// 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.
|
|
|
|
|
2015-08-28 15:33:40 +00:00
|
|
|
// +build darwin dragonfly freebsd !android,linux netbsd openbsd solaris
|
2012-03-27 23:13:14 +00:00
|
|
|
// +build cgo
|
|
|
|
|
|
|
|
package user
|
|
|
|
|
|
|
|
import (
|
|
|
|
"fmt"
|
|
|
|
"strconv"
|
|
|
|
"strings"
|
|
|
|
"syscall"
|
|
|
|
"unsafe"
|
|
|
|
)
|
|
|
|
|
|
|
|
/*
|
|
|
|
#include <unistd.h>
|
|
|
|
#include <sys/types.h>
|
|
|
|
#include <pwd.h>
|
|
|
|
#include <stdlib.h>
|
|
|
|
|
|
|
|
static int mygetpwuid_r(int uid, struct passwd *pwd,
|
|
|
|
char *buf, size_t buflen, struct passwd **result) {
|
|
|
|
return getpwuid_r(uid, pwd, buf, buflen, result);
|
|
|
|
}
|
|
|
|
*/
|
|
|
|
|
|
|
|
// bytePtrToString takes a NUL-terminated array of bytes and convert
|
|
|
|
// it to a Go string.
|
|
|
|
func bytePtrToString(p *byte) string {
|
|
|
|
a := (*[10000]byte)(unsafe.Pointer(p))
|
|
|
|
i := 0
|
|
|
|
for a[i] != 0 {
|
|
|
|
i++
|
|
|
|
}
|
|
|
|
return string(a[:i])
|
|
|
|
}
|
|
|
|
|
2014-09-21 17:33:12 +00:00
|
|
|
func current() (*User, error) {
|
|
|
|
return lookupUnix(syscall.Getuid(), "", false)
|
2012-03-27 23:13:14 +00:00
|
|
|
}
|
|
|
|
|
2014-09-21 17:33:12 +00:00
|
|
|
func lookup(username string) (*User, error) {
|
|
|
|
return lookupUnix(-1, username, true)
|
2012-03-27 23:13:14 +00:00
|
|
|
}
|
|
|
|
|
2014-09-21 17:33:12 +00:00
|
|
|
func lookupId(uid string) (*User, error) {
|
2012-03-27 23:13:14 +00:00
|
|
|
i, e := strconv.Atoi(uid)
|
|
|
|
if e != nil {
|
|
|
|
return nil, e
|
|
|
|
}
|
2014-09-21 17:33:12 +00:00
|
|
|
return lookupUnix(i, "", false)
|
2012-03-27 23:13:14 +00:00
|
|
|
}
|
|
|
|
|
2014-09-21 17:33:12 +00:00
|
|
|
func lookupUnix(uid int, username string, lookupByName bool) (*User, error) {
|
2012-03-27 23:13:14 +00:00
|
|
|
var pwd syscall.Passwd
|
|
|
|
var result *syscall.Passwd
|
|
|
|
|
|
|
|
// FIXME: Should let buf grow if necessary.
|
|
|
|
const bufSize = 1024
|
|
|
|
buf := make([]byte, bufSize)
|
|
|
|
if lookupByName {
|
2014-09-21 17:33:12 +00:00
|
|
|
p := syscall.StringBytePtr(username)
|
|
|
|
syscall.Entersyscall()
|
|
|
|
rv := libc_getpwnam_r(p,
|
2012-03-27 23:13:14 +00:00
|
|
|
&pwd,
|
|
|
|
&buf[0],
|
|
|
|
bufSize,
|
|
|
|
&result)
|
2014-09-21 17:33:12 +00:00
|
|
|
syscall.Exitsyscall()
|
2012-03-27 23:13:14 +00:00
|
|
|
if rv != 0 {
|
|
|
|
return nil, fmt.Errorf("user: lookup username %s: %s", username, syscall.GetErrno())
|
|
|
|
}
|
|
|
|
if result == nil {
|
|
|
|
return nil, UnknownUserError(username)
|
|
|
|
}
|
|
|
|
} else {
|
2014-09-21 17:33:12 +00:00
|
|
|
syscall.Entersyscall()
|
2012-03-27 23:13:14 +00:00
|
|
|
rv := libc_getpwuid_r(syscall.Uid_t(uid),
|
|
|
|
&pwd,
|
|
|
|
&buf[0],
|
|
|
|
bufSize,
|
|
|
|
&result)
|
2014-09-21 17:33:12 +00:00
|
|
|
syscall.Exitsyscall()
|
2012-03-27 23:13:14 +00:00
|
|
|
if rv != 0 {
|
|
|
|
return nil, fmt.Errorf("user: lookup userid %d: %s", uid, syscall.GetErrno())
|
|
|
|
}
|
|
|
|
if result == nil {
|
|
|
|
return nil, UnknownUserIdError(uid)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
u := &User{
|
|
|
|
Uid: strconv.Itoa(int(pwd.Pw_uid)),
|
|
|
|
Gid: strconv.Itoa(int(pwd.Pw_gid)),
|
|
|
|
Username: bytePtrToString((*byte)(unsafe.Pointer(pwd.Pw_name))),
|
|
|
|
Name: bytePtrToString((*byte)(unsafe.Pointer(pwd.Pw_gecos))),
|
|
|
|
HomeDir: bytePtrToString((*byte)(unsafe.Pointer(pwd.Pw_dir))),
|
|
|
|
}
|
|
|
|
// 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."
|
|
|
|
if i := strings.Index(u.Name, ","); i >= 0 {
|
|
|
|
u.Name = u.Name[:i]
|
|
|
|
}
|
|
|
|
return u, nil
|
|
|
|
}
|