From d6e5cd6b00f598500b59f7d204d5e4c9d1c39573 Mon Sep 17 00:00:00 2001 From: Luke Shumaker Date: Sat, 4 Feb 2017 17:25:55 -0500 Subject: nshd: db_pam: gut; only support pam_sm_chauthtok() --- go/src/nshd/nslcd_backend/db_pam.go | 98 ++++++++++++++----------------------- 1 file changed, 38 insertions(+), 60 deletions(-) diff --git a/go/src/nshd/nslcd_backend/db_pam.go b/go/src/nshd/nslcd_backend/db_pam.go index b704620..55a0641 100644 --- a/go/src/nshd/nslcd_backend/db_pam.go +++ b/go/src/nshd/nslcd_backend/db_pam.go @@ -1,4 +1,4 @@ -// Copyright 2015-2016 Luke Shumaker . +// Copyright 2015-2017 Luke Shumaker . // // This is free software; you can redistribute it and/or // modify it under the terms of the GNU General Public License as @@ -20,11 +20,11 @@ import ( "fmt" "os" - "nshd/util" "nshd/nshd_files" + "nshd/util" - s "golang.org/x/sys/unix" p "git.lukeshu.com/go/libnslcd/nslcd_proto" + s "golang.org/x/sys/unix" "git.lukeshu.com/go/libgnulinux/crypt" "git.lukeshu.com/go/libsystemd/sd_daemon" @@ -42,6 +42,7 @@ func hashPassword(newPassword string, oldHash string) string { sd_daemon.Log.Err("Could not generate a random string") str = "" } + // "$6$" is SHA-512; see crypt(3) for others salt = "$6$" + str + "$" } return crypt.Crypt(newPassword, salt) @@ -55,6 +56,21 @@ func dirExists(path string) bool { return stat.IsDir() } +func (o *Hackers) canChangePassword(user nshd_files.User, oldpassword string) bool { + // special hack: if the old password is not + // set, but the home directory exists, let the + // user set their password + if user.Passwd.PwHash == "!" && dirExists(user.Passwd.HomeDir) { + return true + } + + return checkPassword(oldpassword, user.Passwd.PwHash) +} + +// We don't actually use this for authentication (we let pam_unix.so +// call NSS getspnam(3), which will call our Shadow_ByName()), but +// pam_ldap.so calls this as a pre-flight check for +// pam_sm_chauthtok()/PAM_PwMod(). func (o *Hackers) PAM_Authentication(cred s.Ucred, req p.Request_PAM_Authentication) <-chan p.PAM_Authentication { o.lock.RLock() ret := make(chan p.PAM_Authentication) @@ -63,6 +79,8 @@ func (o *Hackers) PAM_Authentication(cred s.Ucred, req p.Request_PAM_Authenticat defer close(ret) if len(req.UserName) == 0 && len(req.Password) == 0 && cred.Uid == 0 { + // Being called by root; root can do what root + // wants. ret <- p.PAM_Authentication{ AuthenticationResult: p.NSLCD_PAM_SUCCESS, UserName: "", @@ -76,65 +94,31 @@ func (o *Hackers) PAM_Authentication(cred s.Ucred, req p.Request_PAM_Authenticat if uid < 0 { return } - user := o.users[uid] - obj := p.PAM_Authentication{ - AuthenticationResult: p.NSLCD_PAM_AUTH_ERR, - UserName: "", - AuthorizationResult: p.NSLCD_PAM_AUTH_ERR, - AuthorizationError: "", - } - if checkPassword(req.Password, user.Passwd.PwHash) { - obj.AuthenticationResult = p.NSLCD_PAM_SUCCESS - obj.AuthorizationResult = obj.AuthenticationResult - obj.UserName = user.Passwd.Name - } - ret <- obj - }() - return ret -} - -func (o *Hackers) PAM_Authorization(cred s.Ucred, req p.Request_PAM_Authorization) <-chan p.PAM_Authorization { - o.lock.RLock() - ret := make(chan p.PAM_Authorization) - go func() { - defer o.lock.RUnlock() - defer close(ret) - uid := o.name2uid(req.UserName) - if uid < 0 { + if o.canChangePassword(user, req.Password) { + // Success + ret <- p.PAM_Authentication{ + AuthenticationResult: p.NSLCD_PAM_SUCCESS, + UserName: user.Passwd.Name, + AuthorizationResult: p.NSLCD_PAM_SUCCESS, + AuthorizationError: "", + } return - } - ret <- p.PAM_Authorization{ - Result: p.NSLCD_PAM_SUCCESS, - Error: "", - } - }() - return ret -} - -const alphabet = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789" - -func (o *Hackers) PAM_SessionOpen(cred s.Ucred, req p.Request_PAM_SessionOpen) <-chan p.PAM_SessionOpen { - ret := make(chan p.PAM_SessionOpen) - go func() { - defer close(ret) - - sessionid, err := util.RandomString(alphabet, 24) - if err != nil { + } else { + // Failure + ret <- p.PAM_Authentication{ + AuthenticationResult: p.NSLCD_PAM_AUTH_ERR, + UserName: "", + AuthorizationResult: p.NSLCD_PAM_AUTH_ERR, + AuthorizationError: fmt.Sprintf("password change failed: %s", "Old password did not match"), + } return } - ret <- p.PAM_SessionOpen{SessionID: sessionid} }() return ret } -func (o *Hackers) PAM_SessionClose(cred s.Ucred, req p.Request_PAM_SessionClose) <-chan p.PAM_SessionClose { - ret := make(chan p.PAM_SessionClose) - go close(ret) - return ret -} - func (o *Hackers) PAM_PwMod(cred s.Ucred, req p.Request_PAM_PwMod) <-chan p.PAM_PwMod { ret := make(chan p.PAM_PwMod) o.lock.Lock() @@ -152,13 +136,7 @@ func (o *Hackers) PAM_PwMod(cred s.Ucred, req p.Request_PAM_PwMod) <-chan p.PAM_ if req.AsRoot == 1 && cred.Uid == 0 { goto update } - // special hack: if the old password is not - // set, but the home directory exists, let the - // user set their password - if user.Passwd.PwHash == "!" && dirExists(user.Passwd.HomeDir) { - goto update - } - if !checkPassword(req.OldPassword, user.Passwd.PwHash) { + if !o.canChangePassword(user, req.OldPassword) { ret <- p.PAM_PwMod{ Result: p.NSLCD_PAM_PERM_DENIED, Error: fmt.Sprintf("password change failed: %s", "Old password did not match"), -- cgit v1.2.2