Initial import
This commit is contained in:
105
auth/system_linux.go
Normal file
105
auth/system_linux.go
Normal file
@@ -0,0 +1,105 @@
|
||||
//go:build linux
|
||||
|
||||
package auth
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"errors"
|
||||
"os"
|
||||
"os/user"
|
||||
"path/filepath"
|
||||
|
||||
"github.com/msteinert/pam"
|
||||
"golang.org/x/crypto/ssh"
|
||||
)
|
||||
|
||||
type system struct{}
|
||||
|
||||
type systemPrincipal struct {
|
||||
*user.User
|
||||
attributes Attributes
|
||||
}
|
||||
|
||||
func newSystemPrincipal(name string) (*systemPrincipal, error) {
|
||||
u, err := user.Lookup(name)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
a := Attributes{
|
||||
Custom: make(map[string]any),
|
||||
}
|
||||
if gids, err := u.GroupIds(); err == nil {
|
||||
a.Custom["groups"] = gids
|
||||
for _, gid := range gids {
|
||||
if g, err := user.LookupGroupId(gid); err == nil {
|
||||
a.Groups = append(a.Groups, g.Name)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return &systemPrincipal{
|
||||
User: u,
|
||||
attributes: a,
|
||||
}, nil
|
||||
}
|
||||
|
||||
func (u systemPrincipal) Type() string {
|
||||
return "user"
|
||||
}
|
||||
|
||||
func (u systemPrincipal) Identity() string {
|
||||
return u.Name
|
||||
}
|
||||
|
||||
func (u systemPrincipal) Attributes() Attributes {
|
||||
return u.attributes
|
||||
}
|
||||
|
||||
func SystemPassword() Password {
|
||||
return system{}
|
||||
}
|
||||
|
||||
func (system) VerifyPassword(username, password string) (Principal, error) {
|
||||
t, err := pam.StartFunc("sshd", username, func(s pam.Style, msg string) (string, error) {
|
||||
switch s {
|
||||
case pam.PromptEchoOff:
|
||||
return password, nil
|
||||
case pam.PromptEchoOn:
|
||||
return username, nil
|
||||
default:
|
||||
return "", errors.New("unrecognized message style")
|
||||
}
|
||||
})
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if err = t.Authenticate(0); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return newSystemPrincipal(username)
|
||||
}
|
||||
|
||||
func (system) VerifyPublicKey(username string, key ssh.PublicKey) (Principal, error) {
|
||||
p, err := newSystemPrincipal(username)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
rest, err := os.ReadFile(filepath.Join(p.HomeDir, ".ssh", "authorized_keys"))
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
for len(rest) > 0 {
|
||||
var out ssh.PublicKey
|
||||
if out, _, _, rest, err = ssh.ParseAuthorizedKey(rest); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if bytes.Equal(out.Marshal(), key.Marshal()) {
|
||||
return p, nil
|
||||
}
|
||||
}
|
||||
return nil, ErrAuthorized
|
||||
}
|
Reference in New Issue
Block a user