From 1f87babb40b64892bf090e9ed1bcc71468c51015 Mon Sep 17 00:00:00 2001 From: Luke Shumaker Date: Wed, 2 Sep 2015 12:59:53 -0600 Subject: Implement all of hackers.git, except the group DB --- src/nshd/hackers_git/check_password.go | 29 ++++++++++++ src/nshd/hackers_git/db_group.go | 3 +- src/nshd/hackers_git/db_pam.go | 70 +++++++++++++++++++++++------ src/nshd/hackers_git/db_passwd.go | 78 ++++++++++++++++++++++++++++---- src/nshd/hackers_git/db_shadow.go | 82 +++++++++++++++++++++++++++++++--- src/nshd/hackers_git/hackers.go | 9 ++++ 6 files changed, 241 insertions(+), 30 deletions(-) create mode 100644 src/nshd/hackers_git/check_password.go (limited to 'src') diff --git a/src/nshd/hackers_git/check_password.go b/src/nshd/hackers_git/check_password.go new file mode 100644 index 0000000..c112641 --- /dev/null +++ b/src/nshd/hackers_git/check_password.go @@ -0,0 +1,29 @@ +package hackers_git + +import "unsafe" + +/* +#cgo LDFLAGS: -lcrypt +#define _GNU_SOURCE // for crypt_r(3) in crypt.h +#include // for free(3) +#include // for crypt_r(3) +#include // for strcmp(3) and memset(3) +int check_password(const char *password, const char *hash) +{ + int ret; + struct crypt_data data; + data.initialized = 0; + ret = (strcmp(crypt_r(password, hash, &data), hash) == 0); + memset(&data, 0, sizeof(data)); + return ret; +} +*/ +import "C" + +func check_password(password string, hash string) bool { + cpassword := C.CString(password) + defer C.free(unsafe.Pointer(cpassword)) + chash := C.CString(hash) + defer C.free(unsafe.Pointer(chash)) + return C.check_password(cpassword, chash) != 0 +} diff --git a/src/nshd/hackers_git/db_group.go b/src/nshd/hackers_git/db_group.go index 5277094..b72dcfe 100644 --- a/src/nshd/hackers_git/db_group.go +++ b/src/nshd/hackers_git/db_group.go @@ -1,5 +1,5 @@ package hackers_git - +/* import p "nslcd_proto" func (o *Hackers) Group_ByName(cred p.Ucred, req p.Request_Group_ByName) p.Group_Enumerator { @@ -26,3 +26,4 @@ func (o *Hackers) Group_All(cred p.Ucred, req p.Request_Group_All) p.Group_Enume // TODO return nil } +*/ diff --git a/src/nshd/hackers_git/db_pam.go b/src/nshd/hackers_git/db_pam.go index a133e88..7c20a56 100644 --- a/src/nshd/hackers_git/db_pam.go +++ b/src/nshd/hackers_git/db_pam.go @@ -1,28 +1,72 @@ package hackers_git -import p "nslcd_proto" +import ( + "crypto/rand" + "math/big" + p "nslcd_proto" + "nslcd_proto/util" +) func (o *Hackers) PAM_Authentication(cred p.Ucred, req p.Request_PAM_Authentication) p.PAM_Authentication_Enumerator { o.lock.RLock() defer o.lock.RUnlock() - // TODO - return nil + + uid := o.name2uid(req.UserName) + if uid < 0 { + return util.PAM_Authentication_Ø{} + } + + user := o.users[uid] + ret := p.PAM_Authentication{ + AuthenticationResult: p.NSLCD_PAM_AUTH_ERR, + UserName: "", + AuthorizationResult: p.NSLCD_PAM_AUTH_ERR, + AuthorizationError: "", + } + if check_password(req.Password, user.passwd.PwHash) { + ret.AuthenticationResult = p.NSLCD_PAM_SUCCESS + ret.AuthorizationResult = ret.AuthenticationResult + ret.UserName = user.passwd.Name + } + + return util.New_PAM_Authentication_List([]p.PAM_Authentication{ret}) } + func (o *Hackers) PAM_Authorization(cred p.Ucred, req p.Request_PAM_Authorization) p.PAM_Authorization_Enumerator { o.lock.RLock() defer o.lock.RUnlock() - // TODO - return nil + + uid := o.name2uid(req.UserName) + if uid < 0 { + return util.PAM_Authorization_Ø{} + } + ret := p.PAM_Authorization{ + Result: p.NSLCD_PAM_SUCCESS, + Error: "", + } + + return util.New_PAM_Authorization_List([]p.PAM_Authorization{ret}) } + +const alphabet = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz01234567890" +var alphabet_len = big.NewInt(int64(len(alphabet))) + func (o *Hackers) PAM_SessionOpen(cred p.Ucred, req p.Request_PAM_SessionOpen) p.PAM_SessionOpen_Enumerator { - o.lock.RLock() - defer o.lock.RUnlock() - // TODO - return nil + var sessionid [24]byte + + for i := 0; i < len(sessionid); i++ { + bigint, err := rand.Int(rand.Reader, alphabet_len) + if err != nil { + return util.PAM_SessionOpen_Ø{} + } + sessionid[i] = alphabet[bigint.Int64()] + } + + ret := p.PAM_SessionOpen{SessionID: string(sessionid[:])} + + return util.New_PAM_SessionOpen_List([]p.PAM_SessionOpen{ret}) } + func (o *Hackers) PAM_SessionClose(cred p.Ucred, req p.Request_PAM_SessionClose) p.PAM_SessionClose_Enumerator { - o.lock.RLock() - defer o.lock.RUnlock() - // TODO - return nil + return util.PAM_SessionClose_Ø{} } diff --git a/src/nshd/hackers_git/db_passwd.go b/src/nshd/hackers_git/db_passwd.go index f0a0257..e8a6838 100644 --- a/src/nshd/hackers_git/db_passwd.go +++ b/src/nshd/hackers_git/db_passwd.go @@ -1,22 +1,82 @@ package hackers_git -import p "nslcd_proto" +import ( + p "nslcd_proto" + "nslcd_proto/util" +) + +/* Note that the output password hash value should be one of: + - no password set, allow login without password + ! - used to prevent logins + x - "valid" encrypted password that does not match any valid password + often used to indicate that the password is defined elsewhere + other - encrypted password, in crypt(3) format */ func (o *Hackers) Passwd_ByName(cred p.Ucred, req p.Request_Passwd_ByName) p.Passwd_Enumerator { o.lock.RLock() defer o.lock.RUnlock() - // TODO - return nil + + uid := o.name2uid(string(req)) + if uid < 0 { + return util.Passwd_Ø{} + } + passwd := o.users[uid].passwd + passwd.PwHash = "x" // only put actual hashes in the Shadow DB + + return util.New_Passwd_List([]p.Passwd{passwd}) } + func (o *Hackers) Passwd_ByUID(cred p.Ucred, req p.Request_Passwd_ByUID) p.Passwd_Enumerator { o.lock.RLock() defer o.lock.RUnlock() - // TODO - return nil + + user, found := o.users[int32(req)] + if !found { + return util.Passwd_Ø{} + } + passwd := user.passwd + passwd.PwHash = "x" // only put actual hashes in the Shadow DB + + return util.New_Passwd_List([]p.Passwd{passwd}) } -func (o *Hackers) Passwd_All(cred p.Ucred, req p.Request_Passwd_All) p.Passwd_Enumerator { + +type allPasswdEnumerator struct { + uids []int32 + backend *Hackers + done bool +} + +func (e *allPasswdEnumerator) GetNext() (*p.Passwd, error) { + if len(e.uids) > 0 { + passwd := e.backend.users[e.uids[0]].passwd + passwd.PwHash = "x" // only put actual hashes in the Shadow DB + e.uids = e.uids[1:] + return &passwd, nil + } + if len(e.uids) == 0 && !e.done { + e.done = true + e.backend.lock.RUnlock() + } + return nil, nil +} + +func (e *allPasswdEnumerator) GenericGetNext() (interface{}, error) { + return e.GetNext() +} + +func (o *Hackers) newAllPasswdEnumerator() *allPasswdEnumerator { o.lock.RLock() - defer o.lock.RUnlock() - // TODO - return nil + e := allPasswdEnumerator{ + uids: make([]int32, len(o.users)), + backend: o, + done: false, + } + for uid, _ := range o.users { + e.uids = append(e.uids, uid) + } + return &e +} + +func (o *Hackers) Passwd_All(cred p.Ucred, req p.Request_Passwd_All) p.Passwd_Enumerator { + return o.newAllPasswdEnumerator() } diff --git a/src/nshd/hackers_git/db_shadow.go b/src/nshd/hackers_git/db_shadow.go index 199d89e..08384d9 100644 --- a/src/nshd/hackers_git/db_shadow.go +++ b/src/nshd/hackers_git/db_shadow.go @@ -1,16 +1,84 @@ package hackers_git -import p "nslcd_proto" +import ( + p "nslcd_proto" + "nslcd_proto/util" +) func (o *Hackers) Shadow_ByName(cred p.Ucred, req p.Request_Shadow_ByName) p.Shadow_Enumerator { o.lock.RLock() defer o.lock.RUnlock() - // TODO - return nil + + if cred.Uid != 0 { + return util.Shadow_Ø{} + } + uid := o.name2uid(string(req)) + passwd := o.users[uid].passwd + shadow := p.Shadow{ + Name: passwd.Name, + PwHash: passwd.PwHash, + LastChangeDate: -1, + MinDays: -1, + MaxDays: -1, + WarnDays: -1, + InactDays: -1, + ExpireDate: -1, + Flag: -1, + } + + return util.New_Shadow_List([]p.Shadow{shadow}) } -func (o *Hackers) Shadow_All(cred p.Ucred, req p.Request_Shadow_All) p.Shadow_Enumerator { + +type allShadowEnumerator struct { + uids []int32 + backend *Hackers + done bool +} + +func (e *allShadowEnumerator) GetNext() (*p.Shadow, error) { + if len(e.uids) > 0 { + passwd := e.backend.users[e.uids[0]].passwd + shadow := p.Shadow{ + Name: passwd.Name, + PwHash: passwd.PwHash, + LastChangeDate: -1, + MinDays: -1, + MaxDays: -1, + WarnDays: -1, + InactDays: -1, + ExpireDate: -1, + Flag: -1, + } + e.uids = e.uids[1:] + return &shadow, nil + } + if len(e.uids) == 0 && !e.done { + e.done = true + e.backend.lock.RUnlock() + } + return nil, nil +} + +func (e *allShadowEnumerator) GenericGetNext() (interface{}, error) { + return e.GetNext() +} + +func (o *Hackers) newAllShadowEnumerator() *allShadowEnumerator { o.lock.RLock() - defer o.lock.RUnlock() - // TODO - return nil + e := allShadowEnumerator{ + uids: make([]int32, len(o.users)), + backend: o, + done: false, + } + for uid, _ := range o.users { + e.uids = append(e.uids, uid) + } + return &e +} + +func (o *Hackers) Shadow_All(cred p.Ucred, req p.Request_Shadow_All) p.Shadow_Enumerator { + if cred.Uid != 0 { + return util.Shadow_Ø{} + } + return o.newAllShadowEnumerator() } diff --git a/src/nshd/hackers_git/hackers.go b/src/nshd/hackers_git/hackers.go index 5876613..4a1021a 100644 --- a/src/nshd/hackers_git/hackers.go +++ b/src/nshd/hackers_git/hackers.go @@ -51,3 +51,12 @@ func (o *Hackers) Reload() error { return o.reload() } + +func (o *Hackers) name2uid(name string) int32 { + for uid, data := range o.users { + if data.passwd.Name == name { + return uid + } + } + return -1 +} -- cgit v1.2.3-54-g00ecf