Browse Source

Add (as default) option to use system shadow passwds

Russ Magee 1 year ago
parent
commit
faf4d5c50a
3 changed files with 57 additions and 4 deletions
  1. 1 0
      TODO.txt
  2. 47 3
      auth.go
  3. 9 1
      xsd/xsd.go

+ 1 - 0
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

+ 47 - 3
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.

+ 9 - 1
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