diff options
Diffstat (limited to 'go/parabola_hackers/nslcd_backend/db_pam.go')
-rw-r--r-- | go/parabola_hackers/nslcd_backend/db_pam.go | 167 |
1 files changed, 167 insertions, 0 deletions
diff --git a/go/parabola_hackers/nslcd_backend/db_pam.go b/go/parabola_hackers/nslcd_backend/db_pam.go new file mode 100644 index 0000000..3374170 --- /dev/null +++ b/go/parabola_hackers/nslcd_backend/db_pam.go @@ -0,0 +1,167 @@ +// Copyright 2015-2016 Luke Shumaker <lukeshu@sbcglobal.net>. +// +// This is free software; you can redistribute it and/or +// modify it under the terms of the GNU General Public License as +// published by the Free Software Foundation; either version 2 of +// the License, or (at your option) any later version. +// +// This software is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public +// License along with this manual; if not, see +// <http://www.gnu.org/licenses/>. + +package hackers_nslcd_backend + +import ( + "fmt" + "parabola_hackers" + s "syscall" + + "lukeshu.com/git/go/libgnulinux.git/crypt" + p "lukeshu.com/git/go/libnslcd.git/proto" + "lukeshu.com/git/go/libsystemd.git/sd_daemon/logger" +) + +func checkPassword(password string, hash string) bool { + return crypt.Crypt(password, hash) == hash +} + +func hashPassword(newPassword string, oldHash string) string { + salt := oldHash + if salt == "!" { + str, err := parabola_hackers.RandomString(crypt.SaltAlphabet, 8) + if err != nil { + logger.Err("Could not generate a random string") + str = "" + } + salt = "$6$" + str + "$" + } + return crypt.Crypt(newPassword, salt) +} + +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) + go func() { + defer o.lock.RUnlock() + defer close(ret) + + uid := o.name2uid(req.UserName) + 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 { + 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 := parabola_hackers.RandomString(alphabet, 24) + if err != nil { + 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() + go func() { + defer close(ret) + defer o.lock.Unlock() + + uid := o.name2uid(req.UserName) + if uid < 0 { + return + } + user := o.users[uid] + + // Check the OldPassword + if req.AsRoot == 1 { + if !checkPassword(req.OldPassword, user.Passwd.PwHash) { + ret <- p.PAM_PwMod{ + Result: p.NSLCD_PAM_PERM_DENIED, + Error: fmt.Sprintf("password change failed: %s", "Old password did not match"), + } + return + } + } + + // Update the PwHash in memory + user.Passwd.PwHash = hashPassword(req.NewPassword, user.Passwd.PwHash) + if user.Passwd.PwHash == "" { + logger.Err("Password hashing failed") + return + } + + // Update the PwHash on disk + passwords := make(map[string]string, len(o.users)) + for _, ouser := range o.users { + passwords[ouser.Passwd.Name] = ouser.Passwd.PwHash + } + passwords[user.Passwd.Name] = user.Passwd.PwHash + err := parabola_hackers.SaveAllPasswords(passwords) + if err != nil { + logger.Err("Writing passwords to disk: %v", err) + return + } + + // Ok, we're done, commit the changes + o.users[uid] = user + ret <- p.PAM_PwMod{ + Result: p.NSLCD_PAM_SUCCESS, + Error: "", + } + }() + return ret +} |