diff --git a/TODO.txt b/TODO.txt index 771a484..9a621fe 100644 --- a/TODO.txt +++ b/TODO.txt @@ -18,6 +18,7 @@ Architecture (parts split out into hkexnet/*, hkexsession.go) (DONE) - Make KEx fully-pluggable: isolate all code to do with Herradura into a KEx-neutral pkg so it can be swapped out for other methods (eg., DH etc.) +(DONE - test branch) - Use system password db (/etc/{passwd,shadow}) Features (DONE) - Support for hkcp (hkex-cp) - secure file copy protocol diff --git a/auth.go b/auth.go index f3c396c..6e0adcb 100644 --- a/auth.go +++ b/auth.go @@ -13,6 +13,7 @@ package xs import ( "bytes" "encoding/csv" + "errors" "fmt" "io" "io/ioutil" @@ -22,13 +23,49 @@ import ( "strings" "github.com/jameskeane/bcrypt" + passlib "gopkg.in/hlandau/passlib.v1" ) -func userExistsOnSystem(who string) bool { - _, userErr := user.Lookup(who) - return userErr == nil +// --------- System passwd/shadow auth routine(s) -------------- +// Verify a password against system standard shadow file +// Note auxilliary fields for expiry policy are *not* inspected. +func VerifyPass(user, password string) (bool, error) { + passlib.UseDefaults(passlib.Defaults20180601) + pwFileData, e := ioutil.ReadFile("/etc/shadow") + if e != nil { + return false, e + } + pwLines := strings.Split(string(pwFileData), "\n") + if len(pwLines) < 1 { + return false, errors.New("Empty shadow file!") + } else { + var line string + var hash string + var idx int + for idx = range pwLines { + line = pwLines[idx] + lFields := strings.Split(line, ":") + if lFields[0] == user { + hash = lFields[1] + break + } + } + if len(hash) == 0 { + return false, errors.New("nil hash!") + } else { + pe := passlib.VerifyNoUpgrade(password, hash) + if pe != nil { + return false, pe + } + } + } + return true, nil } +// --------- End System passwd/shadow auth routine(s) ---------- + +// ------------- xs-local passwd auth routine(s) --------------- + // AuthUserByPasswd checks user login information using a password. // This checks /etc/xs.passwd for auth info, and system /etc/passwd // to cross-check the user actually exists. @@ -84,6 +121,13 @@ func AuthUserByPasswd(username string, auth string, fname string) (valid bool, a return } +// ------------- End xs-local passwd auth routine(s) ----------- + +func userExistsOnSystem(who string) bool { + _, userErr := user.Lookup(who) + return userErr == nil +} + // AuthUserByToken checks user login information against an auth token. // Auth tokens are stored in each user's $HOME/.xs_id and are requested // via the -g option. diff --git a/xsd/xsd.go b/xsd/xsd.go index a7ac458..b1c1e98 100755 --- a/xsd/xsd.go +++ b/xsd/xsd.go @@ -509,6 +509,8 @@ func main() { var dbg bool var laddr string + var useSystemPasswd bool + flag.BoolVar(&vopt, "v", false, "show version") flag.StringVar(&laddr, "l", ":2000", "interface[:port] to listen") flag.StringVar(&kcpMode, "K", "unused", `set to one of ["KCP_NONE","KCP_AES", "KCP_BLOWFISH", "KCP_CAST5", "KCP_SM4", "KCP_SALSA20", "KCP_SIMPLEXOR", "KCP_TEA", "KCP_3DES", "KCP_TWOFISH", "KCP_XTEA"] to use KCP (github.com/xtaci/kcp-go) reliable UDP instead of TCP`) @@ -517,6 +519,7 @@ func main() { flag.UintVar(&chaffFreqMin, "f", 100, "chaff pkt freq min (msecs)") flag.UintVar(&chaffFreqMax, "F", 5000, "chaff pkt freq max (msecs)") flag.UintVar(&chaffBytesMax, "B", 64, "chaff pkt size max (bytes)") + flag.BoolVar(&useSystemPasswd, "s", true, "use system shadow passwds") flag.BoolVar(&dbg, "d", false, "debug logging") flag.Var(&aKEXAlgs, "aK", `List of allowed KEX algs (eg. 'KEXAlgA KEXAlgB ... KEXAlgN') (default allow all)`) @@ -709,7 +712,12 @@ func main() { if xs.AuthUserByToken(string(rec.Who()), string(rec.ConnHost()), string(rec.AuthCookie(true))) { valid = true } else { - valid, allowedCmds = xs.AuthUserByPasswd(string(rec.Who()), string(rec.AuthCookie(true)), "/etc/xs.passwd") + if useSystemPasswd { + //var passErr error + valid, _ /*passErr*/ = xs.VerifyPass(string(rec.Who()), string(rec.AuthCookie(true))) + } else { + valid, allowedCmds = xs.AuthUserByPasswd(string(rec.Who()), string(rec.AuthCookie(true)), "/etc/xs.passwd") + } } // Security scrub