mirror of https://gogs.blitter.com/RLabs/xs
Fixed error in processing of allowed HMAC algs.
xsd: allowed algs default to none if unspecified.
This commit is contained in:
parent
129dce4b08
commit
cfc9ab8590
466
xsd/xsd.go
466
xsd/xsd.go
|
@ -439,9 +439,9 @@ var (
|
||||||
aHMACAlgs allowedHMACAlgs
|
aHMACAlgs allowedHMACAlgs
|
||||||
)
|
)
|
||||||
|
|
||||||
type allowedKEXAlgs []string // TODO
|
type allowedKEXAlgs []string
|
||||||
type allowedCipherAlgs []string // TODO
|
type allowedCipherAlgs []string
|
||||||
type allowedHMACAlgs []string // TODO
|
type allowedHMACAlgs []string
|
||||||
|
|
||||||
func (a allowedKEXAlgs) allowed(k xsnet.KEXAlg) bool {
|
func (a allowedKEXAlgs) allowed(k xsnet.KEXAlg) bool {
|
||||||
for i := 0; i < len(a); i++ {
|
for i := 0; i < len(a); i++ {
|
||||||
|
@ -527,9 +527,33 @@ func main() {
|
||||||
flag.BoolVar(&useSystemPasswd, "s", true, "use system shadow passwds")
|
flag.BoolVar(&useSystemPasswd, "s", true, "use system shadow passwds")
|
||||||
flag.BoolVar(&dbg, "d", false, "debug logging")
|
flag.BoolVar(&dbg, "d", false, "debug logging")
|
||||||
|
|
||||||
flag.Var(&aKEXAlgs, "aK", `List of allowed KEX algs (eg. 'KEXAlgA KEXAlgB ... KEXAlgN') (default allow all)`)
|
flag.Var(&aKEXAlgs, "aK", `Allowed KEX algs (eg. '-aK KEXAlgA -aK KEXAlgB ...') (default: none)
|
||||||
flag.Var(&aCipherAlgs, "aC", `List of allowed ciphers (eg. 'CipherAlgA CipherAlgB ... CipherAlgN') (default allow all)`)
|
KEX_all
|
||||||
flag.Var(&aHMACAlgs, "aH", `List of allowed HMACs (eg. 'HMACAlgA HMACAlgB ... HMACAlgN') (default allow all)`)
|
KEX_HERRADURA256
|
||||||
|
KEX_HERRADURA512
|
||||||
|
KEX_HERRADURA1024
|
||||||
|
KEX_HERRADURA2048
|
||||||
|
KEX_KYBER512
|
||||||
|
KEX_KYBER768
|
||||||
|
KEX_KYBER1024
|
||||||
|
KEX_NEWHOPE
|
||||||
|
KEX_NEWHOPE_SIMPLE
|
||||||
|
KEX_FRODOKEM_1344AES
|
||||||
|
KEX_FRODOKEM_1344SHAKE
|
||||||
|
KEX_FRODOKEM_976AES
|
||||||
|
KEX_FRODOKEM_976SHAKE`)
|
||||||
|
flag.Var(&aCipherAlgs, "aC", `Allowed ciphers (eg. '-aC CAlgA -aC CAlgB ...') (default: none)
|
||||||
|
C_all
|
||||||
|
C_AES_256
|
||||||
|
C_TWOFISH_128
|
||||||
|
C_BLOWFISH_64
|
||||||
|
C_CRYPTMT1
|
||||||
|
C_HOPSCOTCH
|
||||||
|
C_CHACHA20_12`)
|
||||||
|
flag.Var(&aHMACAlgs, "aH", `Allowed HMACs (eg. '-aH HMACAlgA -aH HMACAlgB ...') (default: none)
|
||||||
|
H_all
|
||||||
|
H_SHA256
|
||||||
|
H_SHA512`)
|
||||||
|
|
||||||
flag.Parse()
|
flag.Parse()
|
||||||
|
|
||||||
|
@ -566,17 +590,17 @@ func main() {
|
||||||
|
|
||||||
// Set up allowed algs, if specified (default allow all)
|
// Set up allowed algs, if specified (default allow all)
|
||||||
if len(aKEXAlgs) == 0 {
|
if len(aKEXAlgs) == 0 {
|
||||||
aKEXAlgs = []string{"KEX_all"}
|
aKEXAlgs = []string{"none"}
|
||||||
}
|
}
|
||||||
logger.LogNotice(fmt.Sprintf("Allowed KEXAlgs: %v\n", aKEXAlgs)) // nolint: gosec,errcheck
|
logger.LogNotice(fmt.Sprintf("Allowed KEXAlgs: %v\n", aKEXAlgs)) // nolint: gosec,errcheck
|
||||||
|
|
||||||
if len(aCipherAlgs) == 0 {
|
if len(aCipherAlgs) == 0 {
|
||||||
aCipherAlgs = []string{"C_all"}
|
aCipherAlgs = []string{"none"}
|
||||||
}
|
}
|
||||||
logger.LogNotice(fmt.Sprintf("Allowed CipherAlgs: %v\n", aCipherAlgs)) // nolint: gosec,errcheck
|
logger.LogNotice(fmt.Sprintf("Allowed CipherAlgs: %v\n", aCipherAlgs)) // nolint: gosec,errcheck
|
||||||
|
|
||||||
if len(aHMACAlgs) == 0 {
|
if len(aHMACAlgs) == 0 {
|
||||||
aHMACAlgs = []string{"H_all"}
|
aHMACAlgs = []string{"none"}
|
||||||
}
|
}
|
||||||
logger.LogNotice(fmt.Sprintf("Allowed HMACAlgs: %v\n", aHMACAlgs)) // nolint: gosec,errcheck
|
logger.LogNotice(fmt.Sprintf("Allowed HMACAlgs: %v\n", aHMACAlgs)) // nolint: gosec,errcheck
|
||||||
|
|
||||||
|
@ -620,233 +644,235 @@ func main() {
|
||||||
conn, err := l.Accept()
|
conn, err := l.Accept()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Printf("Accept() got error(%v), hanging up.\n", err)
|
log.Printf("Accept() got error(%v), hanging up.\n", err)
|
||||||
} else if !aKEXAlgs.allowed(conn.KEX()) {
|
|
||||||
log.Printf("Accept() rejected for banned KEX alg %d, hanging up.\n", conn.KEX())
|
|
||||||
conn.SetStatus(xsnet.CSEKEXAlgDenied)
|
|
||||||
conn.Close()
|
|
||||||
} else if !aCipherAlgs.allowed(conn.CAlg()) {
|
|
||||||
log.Printf("Accept() rejected for banned Cipher alg %d, hanging up.\n", conn.CAlg())
|
|
||||||
conn.SetStatus(xsnet.CSECipherAlgDenied)
|
|
||||||
conn.Close()
|
|
||||||
} else if !aHMACAlgs.allowed(conn.HAlg()) {
|
|
||||||
log.Printf("Accept() rejected for banned HMAC alg %d, hanging up.\n", conn.HAlg())
|
|
||||||
conn.SetStatus(xsnet.CSEHMACAlgDenied)
|
|
||||||
conn.Close()
|
|
||||||
} else {
|
} else {
|
||||||
log.Println("Accepted client")
|
if !aKEXAlgs.allowed(conn.KEX()) {
|
||||||
|
log.Printf("Accept() rejected for banned KEX alg %d, hanging up.\n", conn.KEX())
|
||||||
|
conn.SetStatus(xsnet.CSEKEXAlgDenied)
|
||||||
|
conn.Close()
|
||||||
|
} else if !aCipherAlgs.allowed(conn.CAlg()) {
|
||||||
|
log.Printf("Accept() rejected for banned Cipher alg %d, hanging up.\n", conn.CAlg())
|
||||||
|
conn.SetStatus(xsnet.CSECipherAlgDenied)
|
||||||
|
conn.Close()
|
||||||
|
} else if !aHMACAlgs.allowed(conn.HAlg()) {
|
||||||
|
log.Printf("Accept() rejected for banned HMAC alg %d, hanging up.\n", conn.HAlg())
|
||||||
|
conn.SetStatus(xsnet.CSEHMACAlgDenied)
|
||||||
|
conn.Close()
|
||||||
|
} else {
|
||||||
|
log.Println("Accepted client")
|
||||||
|
|
||||||
// Set up chaffing to client
|
// Set up chaffing to client
|
||||||
// Will only start when runShellAs() is called
|
// Will only start when runShellAs() is called
|
||||||
// after stdin/stdout are hooked up
|
// after stdin/stdout are hooked up
|
||||||
conn.SetupChaff(chaffFreqMin, chaffFreqMax, chaffBytesMax) // configure server->client chaffing
|
conn.SetupChaff(chaffFreqMin, chaffFreqMax, chaffBytesMax) // configure server->client chaffing
|
||||||
|
|
||||||
// Handle the connection in a new goroutine.
|
// Handle the connection in a new goroutine.
|
||||||
// The loop then returns to accepting, so that
|
// The loop then returns to accepting, so that
|
||||||
// multiple connections may be served concurrently.
|
// multiple connections may be served concurrently.
|
||||||
go func(hc *xsnet.Conn) (e error) {
|
go func(hc *xsnet.Conn) (e error) {
|
||||||
defer hc.Close() // nolint: errcheck
|
defer hc.Close() // nolint: errcheck
|
||||||
|
|
||||||
// Start login timeout here and disconnect if user/pass phase stalls
|
// Start login timeout here and disconnect if user/pass phase stalls
|
||||||
loginTimeout := time.AfterFunc(30*time.Second, func() {
|
loginTimeout := time.AfterFunc(30*time.Second, func() {
|
||||||
logger.LogNotice(fmt.Sprintln("Login timed out")) // nolint: errcheck,gosec
|
logger.LogNotice(fmt.Sprintln("Login timed out")) // nolint: errcheck,gosec
|
||||||
hc.Write([]byte{0}) // nolint: gosec,errcheck
|
hc.Write([]byte{0}) // nolint: gosec,errcheck
|
||||||
hc.Close()
|
hc.Close()
|
||||||
})
|
})
|
||||||
|
|
||||||
//We use io.ReadFull() here to guarantee we consume
|
//We use io.ReadFull() here to guarantee we consume
|
||||||
//just the data we want for the xs.Session, and no more.
|
//just the data we want for the xs.Session, and no more.
|
||||||
//Otherwise data will be sitting in the channel that isn't
|
//Otherwise data will be sitting in the channel that isn't
|
||||||
//passed down to the command handlers.
|
//passed down to the command handlers.
|
||||||
var rec xs.Session
|
var rec xs.Session
|
||||||
var len1, len2, len3, len4, len5, len6 uint32
|
var len1, len2, len3, len4, len5, len6 uint32
|
||||||
|
|
||||||
n, err := fmt.Fscanf(hc, "%d %d %d %d %d %d\n", &len1, &len2, &len3, &len4, &len5, &len6)
|
n, err := fmt.Fscanf(hc, "%d %d %d %d %d %d\n", &len1, &len2, &len3, &len4, &len5, &len6)
|
||||||
log.Printf("xs.Session read:%d %d %d %d %d %d\n", len1, len2, len3, len4, len5, len6)
|
log.Printf("xs.Session read:%d %d %d %d %d %d\n", len1, len2, len3, len4, len5, len6)
|
||||||
|
|
||||||
if err != nil || n < 6 {
|
if err != nil || n < 6 {
|
||||||
log.Println("[Bad xs.Session fmt]")
|
log.Println("[Bad xs.Session fmt]")
|
||||||
return err
|
return err
|
||||||
}
|
|
||||||
|
|
||||||
tmp := make([]byte, len1)
|
|
||||||
_, err = io.ReadFull(hc, tmp)
|
|
||||||
if err != nil {
|
|
||||||
log.Println("[Bad xs.Session.Op]")
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
rec.SetOp(tmp)
|
|
||||||
|
|
||||||
tmp = make([]byte, len2)
|
|
||||||
_, err = io.ReadFull(hc, tmp)
|
|
||||||
if err != nil {
|
|
||||||
log.Println("[Bad xs.Session.Who]")
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
rec.SetWho(tmp)
|
|
||||||
|
|
||||||
tmp = make([]byte, len3)
|
|
||||||
_, err = io.ReadFull(hc, tmp)
|
|
||||||
if err != nil {
|
|
||||||
log.Println("[Bad xs.Session.ConnHost]")
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
rec.SetConnHost(tmp)
|
|
||||||
|
|
||||||
tmp = make([]byte, len4)
|
|
||||||
_, err = io.ReadFull(hc, tmp)
|
|
||||||
if err != nil {
|
|
||||||
log.Println("[Bad xs.Session.TermType]")
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
rec.SetTermType(tmp)
|
|
||||||
|
|
||||||
tmp = make([]byte, len5)
|
|
||||||
_, err = io.ReadFull(hc, tmp)
|
|
||||||
if err != nil {
|
|
||||||
log.Println("[Bad xs.Session.Cmd]")
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
rec.SetCmd(tmp)
|
|
||||||
|
|
||||||
tmp = make([]byte, len6)
|
|
||||||
_, err = io.ReadFull(hc, tmp)
|
|
||||||
if err != nil {
|
|
||||||
log.Println("[Bad xs.Session.AuthCookie]")
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
rec.SetAuthCookie(tmp)
|
|
||||||
|
|
||||||
log.Printf("[xs.Session: op:%c who:%s connhost:%s cmd:%s auth:****]\n",
|
|
||||||
rec.Op()[0], string(rec.Who()), string(rec.ConnHost()), string(rec.Cmd()))
|
|
||||||
|
|
||||||
var valid bool
|
|
||||||
var allowedCmds string // Currently unused
|
|
||||||
if xs.AuthUserByToken(xs.NewAuthCtx(), string(rec.Who()), string(rec.ConnHost()), string(rec.AuthCookie(true))) {
|
|
||||||
valid = true
|
|
||||||
} else {
|
|
||||||
if useSystemPasswd {
|
|
||||||
//var passErr error
|
|
||||||
valid, _ /*passErr*/ = xs.VerifyPass(xs.NewAuthCtx(), string(rec.Who()), string(rec.AuthCookie(true)))
|
|
||||||
} else {
|
|
||||||
valid, allowedCmds = xs.AuthUserByPasswd(xs.NewAuthCtx(), string(rec.Who()), string(rec.AuthCookie(true)), "/etc/xs.passwd")
|
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
_ = loginTimeout.Stop()
|
tmp := make([]byte, len1)
|
||||||
// Security scrub
|
_, err = io.ReadFull(hc, tmp)
|
||||||
rec.ClearAuthCookie()
|
if err != nil {
|
||||||
|
log.Println("[Bad xs.Session.Op]")
|
||||||
// Tell client if auth was valid
|
return err
|
||||||
if valid {
|
|
||||||
hc.Write([]byte{1}) // nolint: gosec,errcheck
|
|
||||||
} else {
|
|
||||||
logger.LogNotice(fmt.Sprintln("Invalid user", string(rec.Who()))) // nolint: errcheck,gosec
|
|
||||||
hc.Write([]byte{0}) // nolint: gosec,errcheck
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
log.Printf("[allowedCmds:%s]\n", allowedCmds)
|
|
||||||
|
|
||||||
if rec.Op()[0] == 'A' {
|
|
||||||
// Generate automated login token
|
|
||||||
addr := hc.RemoteAddr()
|
|
||||||
hname := goutmp.GetHost(addr.String())
|
|
||||||
logger.LogNotice(fmt.Sprintf("[Generating autologin token for [%s@%s]]\n", rec.Who(), hname)) // nolint: gosec,errcheck
|
|
||||||
token := GenAuthToken(string(rec.Who()), string(rec.ConnHost()))
|
|
||||||
tokenCmd := fmt.Sprintf("echo \"%s\" | tee -a ~/.xs_id", token)
|
|
||||||
cmdStatus, runErr := runShellAs(string(rec.Who()), hname, string(rec.TermType()), tokenCmd, false, hc, chaffEnabled)
|
|
||||||
// Returned hopefully via an EOF or exit/logout;
|
|
||||||
// Clear current op so user can enter next, or EOF
|
|
||||||
rec.SetOp([]byte{0})
|
|
||||||
if runErr != nil {
|
|
||||||
logger.LogErr(fmt.Sprintf("[Error generating autologin token for %s@%s]\n", rec.Who(), hname)) // nolint: gosec,errcheck
|
|
||||||
} else {
|
|
||||||
log.Printf("[Autologin token generation completed for %s@%s, status %d]\n", rec.Who(), hname, cmdStatus)
|
|
||||||
hc.SetStatus(xsnet.CSOType(cmdStatus))
|
|
||||||
}
|
}
|
||||||
} else if rec.Op()[0] == 'c' {
|
rec.SetOp(tmp)
|
||||||
// Non-interactive command
|
|
||||||
addr := hc.RemoteAddr()
|
|
||||||
hname := goutmp.GetHost(addr.String())
|
|
||||||
logger.LogNotice(fmt.Sprintf("[Running command for [%s@%s]]\n", rec.Who(), hname)) // nolint: gosec,errcheck
|
|
||||||
cmdStatus, runErr := runShellAs(string(rec.Who()), hname, string(rec.TermType()), string(rec.Cmd()), false, hc, chaffEnabled)
|
|
||||||
// Returned hopefully via an EOF or exit/logout;
|
|
||||||
// Clear current op so user can enter next, or EOF
|
|
||||||
rec.SetOp([]byte{0})
|
|
||||||
if runErr != nil {
|
|
||||||
logger.LogErr(fmt.Sprintf("[Error spawning cmd for %s@%s]\n", rec.Who(), hname)) // nolint: gosec,errcheck
|
|
||||||
} else {
|
|
||||||
logger.LogNotice(fmt.Sprintf("[Command completed for %s@%s, status %d]\n", rec.Who(), hname, cmdStatus)) // nolint: gosec,errcheck
|
|
||||||
hc.SetStatus(xsnet.CSOType(cmdStatus))
|
|
||||||
}
|
|
||||||
} else if rec.Op()[0] == 's' {
|
|
||||||
// Interactive session
|
|
||||||
addr := hc.RemoteAddr()
|
|
||||||
hname := goutmp.GetHost(addr.String())
|
|
||||||
logger.LogNotice(fmt.Sprintf("[Running shell for [%s@%s]]\n", rec.Who(), hname)) // nolint: gosec,errcheck
|
|
||||||
|
|
||||||
cmdStatus, runErr := runShellAs(string(rec.Who()), hname, string(rec.TermType()), string(rec.Cmd()), true, hc, chaffEnabled)
|
tmp = make([]byte, len2)
|
||||||
// Returned hopefully via an EOF or exit/logout;
|
_, err = io.ReadFull(hc, tmp)
|
||||||
// Clear current op so user can enter next, or EOF
|
if err != nil {
|
||||||
rec.SetOp([]byte{0})
|
log.Println("[Bad xs.Session.Who]")
|
||||||
if runErr != nil {
|
return err
|
||||||
Log.Err(fmt.Sprintf("[Error spawning shell for %s@%s]\n", rec.Who(), hname)) // nolint: gosec,errcheck
|
|
||||||
} else {
|
|
||||||
logger.LogNotice(fmt.Sprintf("[Shell completed for %s@%s, status %d]\n", rec.Who(), hname, cmdStatus)) // nolint: gosec,errcheck
|
|
||||||
hc.SetStatus(xsnet.CSOType(cmdStatus))
|
|
||||||
}
|
}
|
||||||
} else if rec.Op()[0] == 'D' {
|
rec.SetWho(tmp)
|
||||||
// File copy (destination) operation - client copy to server
|
|
||||||
log.Printf("[Client->Server copy]\n")
|
|
||||||
addr := hc.RemoteAddr()
|
|
||||||
hname := goutmp.GetHost(addr.String())
|
|
||||||
logger.LogNotice(fmt.Sprintf("[c->s copy for %s@%s]\n", rec.Who(), hname)) // nolint: gosec,errcheck
|
|
||||||
cmdStatus, runErr := runClientToServerCopyAs(string(rec.Who()), string(rec.TermType()), hc, string(rec.Cmd()), chaffEnabled)
|
|
||||||
// Returned hopefully via an EOF or exit/logout;
|
|
||||||
// Clear current op so user can enter next, or EOF
|
|
||||||
rec.SetOp([]byte{0})
|
|
||||||
if runErr != nil {
|
|
||||||
logger.LogErr(fmt.Sprintf("[c->s copy error for %s@%s]\n", rec.Who(), hname)) // nolint: gosec,errcheck
|
|
||||||
} else {
|
|
||||||
logger.LogNotice(fmt.Sprintf("[c->s copy completed for %s@%s, status %d]\n", rec.Who(), hname, cmdStatus)) // nolint: gosec,errcheck
|
|
||||||
}
|
|
||||||
// TODO: Test this with huge files.. see Bug #22 - do we need to
|
|
||||||
// sync w/sender (client) that we've gotten all data?
|
|
||||||
hc.SetStatus(xsnet.CSOType(cmdStatus))
|
|
||||||
|
|
||||||
// Send CSOExitStatus *before* client closes channel
|
tmp = make([]byte, len3)
|
||||||
s := make([]byte, 4)
|
_, err = io.ReadFull(hc, tmp)
|
||||||
binary.BigEndian.PutUint32(s, cmdStatus)
|
if err != nil {
|
||||||
log.Printf("** cp writing closeStat %d at Close()\n", cmdStatus)
|
log.Println("[Bad xs.Session.ConnHost]")
|
||||||
hc.WritePacket(s, xsnet.CSOExitStatus) // nolint: gosec,errcheck
|
return err
|
||||||
} else if rec.Op()[0] == 'S' {
|
}
|
||||||
// File copy (src) operation - server copy to client
|
rec.SetConnHost(tmp)
|
||||||
log.Printf("[Server->Client copy]\n")
|
|
||||||
addr := hc.RemoteAddr()
|
tmp = make([]byte, len4)
|
||||||
hname := goutmp.GetHost(addr.String())
|
_, err = io.ReadFull(hc, tmp)
|
||||||
logger.LogNotice(fmt.Sprintf("[s->c copy for %s@%s]\n", rec.Who(), hname)) // nolint: gosec,errcheck
|
if err != nil {
|
||||||
cmdStatus, runErr := runServerToClientCopyAs(string(rec.Who()), string(rec.TermType()), hc, string(rec.Cmd()), chaffEnabled)
|
log.Println("[Bad xs.Session.TermType]")
|
||||||
if runErr != nil {
|
return err
|
||||||
logger.LogErr(fmt.Sprintf("[s->c copy error for %s@%s]\n", rec.Who(), hname)) // nolint: gosec,errcheck
|
}
|
||||||
|
rec.SetTermType(tmp)
|
||||||
|
|
||||||
|
tmp = make([]byte, len5)
|
||||||
|
_, err = io.ReadFull(hc, tmp)
|
||||||
|
if err != nil {
|
||||||
|
log.Println("[Bad xs.Session.Cmd]")
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
rec.SetCmd(tmp)
|
||||||
|
|
||||||
|
tmp = make([]byte, len6)
|
||||||
|
_, err = io.ReadFull(hc, tmp)
|
||||||
|
if err != nil {
|
||||||
|
log.Println("[Bad xs.Session.AuthCookie]")
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
rec.SetAuthCookie(tmp)
|
||||||
|
|
||||||
|
log.Printf("[xs.Session: op:%c who:%s connhost:%s cmd:%s auth:****]\n",
|
||||||
|
rec.Op()[0], string(rec.Who()), string(rec.ConnHost()), string(rec.Cmd()))
|
||||||
|
|
||||||
|
var valid bool
|
||||||
|
var allowedCmds string // Currently unused
|
||||||
|
if xs.AuthUserByToken(xs.NewAuthCtx(), string(rec.Who()), string(rec.ConnHost()), string(rec.AuthCookie(true))) {
|
||||||
|
valid = true
|
||||||
} else {
|
} else {
|
||||||
|
if useSystemPasswd {
|
||||||
|
//var passErr error
|
||||||
|
valid, _ /*passErr*/ = xs.VerifyPass(xs.NewAuthCtx(), string(rec.Who()), string(rec.AuthCookie(true)))
|
||||||
|
} else {
|
||||||
|
valid, allowedCmds = xs.AuthUserByPasswd(xs.NewAuthCtx(), string(rec.Who()), string(rec.AuthCookie(true)), "/etc/xs.passwd")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
_ = loginTimeout.Stop()
|
||||||
|
// Security scrub
|
||||||
|
rec.ClearAuthCookie()
|
||||||
|
|
||||||
|
// Tell client if auth was valid
|
||||||
|
if valid {
|
||||||
|
hc.Write([]byte{1}) // nolint: gosec,errcheck
|
||||||
|
} else {
|
||||||
|
logger.LogNotice(fmt.Sprintln("Invalid user", string(rec.Who()))) // nolint: errcheck,gosec
|
||||||
|
hc.Write([]byte{0}) // nolint: gosec,errcheck
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
log.Printf("[allowedCmds:%s]\n", allowedCmds)
|
||||||
|
|
||||||
|
if rec.Op()[0] == 'A' {
|
||||||
|
// Generate automated login token
|
||||||
|
addr := hc.RemoteAddr()
|
||||||
|
hname := goutmp.GetHost(addr.String())
|
||||||
|
logger.LogNotice(fmt.Sprintf("[Generating autologin token for [%s@%s]]\n", rec.Who(), hname)) // nolint: gosec,errcheck
|
||||||
|
token := GenAuthToken(string(rec.Who()), string(rec.ConnHost()))
|
||||||
|
tokenCmd := fmt.Sprintf("echo \"%s\" | tee -a ~/.xs_id", token)
|
||||||
|
cmdStatus, runErr := runShellAs(string(rec.Who()), hname, string(rec.TermType()), tokenCmd, false, hc, chaffEnabled)
|
||||||
// Returned hopefully via an EOF or exit/logout;
|
// Returned hopefully via an EOF or exit/logout;
|
||||||
logger.LogNotice(fmt.Sprintf("[s->c copy completed for %s@%s, status %d]\n", rec.Who(), hname, cmdStatus)) // nolint: gosec,errcheck
|
// Clear current op so user can enter next, or EOF
|
||||||
}
|
rec.SetOp([]byte{0})
|
||||||
// HACK: Bug #22: (xc) Need to wait for rcvr to get final data
|
if runErr != nil {
|
||||||
// TODO: Await specific msg from client to inform they have gotten all data from the tarpipe
|
logger.LogErr(fmt.Sprintf("[Error generating autologin token for %s@%s]\n", rec.Who(), hname)) // nolint: gosec,errcheck
|
||||||
time.Sleep(time.Duration(900 * time.Millisecond)) // Let rcvr set this on setup?
|
} else {
|
||||||
|
log.Printf("[Autologin token generation completed for %s@%s, status %d]\n", rec.Who(), hname, cmdStatus)
|
||||||
|
hc.SetStatus(xsnet.CSOType(cmdStatus))
|
||||||
|
}
|
||||||
|
} else if rec.Op()[0] == 'c' {
|
||||||
|
// Non-interactive command
|
||||||
|
addr := hc.RemoteAddr()
|
||||||
|
hname := goutmp.GetHost(addr.String())
|
||||||
|
logger.LogNotice(fmt.Sprintf("[Running command for [%s@%s]]\n", rec.Who(), hname)) // nolint: gosec,errcheck
|
||||||
|
cmdStatus, runErr := runShellAs(string(rec.Who()), hname, string(rec.TermType()), string(rec.Cmd()), false, hc, chaffEnabled)
|
||||||
|
// Returned hopefully via an EOF or exit/logout;
|
||||||
|
// Clear current op so user can enter next, or EOF
|
||||||
|
rec.SetOp([]byte{0})
|
||||||
|
if runErr != nil {
|
||||||
|
logger.LogErr(fmt.Sprintf("[Error spawning cmd for %s@%s]\n", rec.Who(), hname)) // nolint: gosec,errcheck
|
||||||
|
} else {
|
||||||
|
logger.LogNotice(fmt.Sprintf("[Command completed for %s@%s, status %d]\n", rec.Who(), hname, cmdStatus)) // nolint: gosec,errcheck
|
||||||
|
hc.SetStatus(xsnet.CSOType(cmdStatus))
|
||||||
|
}
|
||||||
|
} else if rec.Op()[0] == 's' {
|
||||||
|
// Interactive session
|
||||||
|
addr := hc.RemoteAddr()
|
||||||
|
hname := goutmp.GetHost(addr.String())
|
||||||
|
logger.LogNotice(fmt.Sprintf("[Running shell for [%s@%s]]\n", rec.Who(), hname)) // nolint: gosec,errcheck
|
||||||
|
|
||||||
// Clear current op so user can enter next, or EOF
|
cmdStatus, runErr := runShellAs(string(rec.Who()), hname, string(rec.TermType()), string(rec.Cmd()), true, hc, chaffEnabled)
|
||||||
rec.SetOp([]byte{0})
|
// Returned hopefully via an EOF or exit/logout;
|
||||||
hc.SetStatus(xsnet.CSOType(cmdStatus))
|
// Clear current op so user can enter next, or EOF
|
||||||
//fmt.Println("Waiting for EOF from other end.")
|
rec.SetOp([]byte{0})
|
||||||
//_, _ = hc.Read(nil /*ackByte*/)
|
if runErr != nil {
|
||||||
//fmt.Println("Got remote end ack.")
|
Log.Err(fmt.Sprintf("[Error spawning shell for %s@%s]\n", rec.Who(), hname)) // nolint: gosec,errcheck
|
||||||
} else {
|
} else {
|
||||||
logger.LogErr(fmt.Sprintln("[Bad xs.Session]")) // nolint: gosec,errcheck
|
logger.LogNotice(fmt.Sprintf("[Shell completed for %s@%s, status %d]\n", rec.Who(), hname, cmdStatus)) // nolint: gosec,errcheck
|
||||||
}
|
hc.SetStatus(xsnet.CSOType(cmdStatus))
|
||||||
return
|
}
|
||||||
}(&conn) // nolint: errcheck
|
} else if rec.Op()[0] == 'D' {
|
||||||
|
// File copy (destination) operation - client copy to server
|
||||||
|
log.Printf("[Client->Server copy]\n")
|
||||||
|
addr := hc.RemoteAddr()
|
||||||
|
hname := goutmp.GetHost(addr.String())
|
||||||
|
logger.LogNotice(fmt.Sprintf("[c->s copy for %s@%s]\n", rec.Who(), hname)) // nolint: gosec,errcheck
|
||||||
|
cmdStatus, runErr := runClientToServerCopyAs(string(rec.Who()), string(rec.TermType()), hc, string(rec.Cmd()), chaffEnabled)
|
||||||
|
// Returned hopefully via an EOF or exit/logout;
|
||||||
|
// Clear current op so user can enter next, or EOF
|
||||||
|
rec.SetOp([]byte{0})
|
||||||
|
if runErr != nil {
|
||||||
|
logger.LogErr(fmt.Sprintf("[c->s copy error for %s@%s]\n", rec.Who(), hname)) // nolint: gosec,errcheck
|
||||||
|
} else {
|
||||||
|
logger.LogNotice(fmt.Sprintf("[c->s copy completed for %s@%s, status %d]\n", rec.Who(), hname, cmdStatus)) // nolint: gosec,errcheck
|
||||||
|
}
|
||||||
|
// TODO: Test this with huge files.. see Bug #22 - do we need to
|
||||||
|
// sync w/sender (client) that we've gotten all data?
|
||||||
|
hc.SetStatus(xsnet.CSOType(cmdStatus))
|
||||||
|
|
||||||
|
// Send CSOExitStatus *before* client closes channel
|
||||||
|
s := make([]byte, 4)
|
||||||
|
binary.BigEndian.PutUint32(s, cmdStatus)
|
||||||
|
log.Printf("** cp writing closeStat %d at Close()\n", cmdStatus)
|
||||||
|
hc.WritePacket(s, xsnet.CSOExitStatus) // nolint: gosec,errcheck
|
||||||
|
} else if rec.Op()[0] == 'S' {
|
||||||
|
// File copy (src) operation - server copy to client
|
||||||
|
log.Printf("[Server->Client copy]\n")
|
||||||
|
addr := hc.RemoteAddr()
|
||||||
|
hname := goutmp.GetHost(addr.String())
|
||||||
|
logger.LogNotice(fmt.Sprintf("[s->c copy for %s@%s]\n", rec.Who(), hname)) // nolint: gosec,errcheck
|
||||||
|
cmdStatus, runErr := runServerToClientCopyAs(string(rec.Who()), string(rec.TermType()), hc, string(rec.Cmd()), chaffEnabled)
|
||||||
|
if runErr != nil {
|
||||||
|
logger.LogErr(fmt.Sprintf("[s->c copy error for %s@%s]\n", rec.Who(), hname)) // nolint: gosec,errcheck
|
||||||
|
} else {
|
||||||
|
// Returned hopefully via an EOF or exit/logout;
|
||||||
|
logger.LogNotice(fmt.Sprintf("[s->c copy completed for %s@%s, status %d]\n", rec.Who(), hname, cmdStatus)) // nolint: gosec,errcheck
|
||||||
|
}
|
||||||
|
// HACK: Bug #22: (xc) Need to wait for rcvr to get final data
|
||||||
|
// TODO: Await specific msg from client to inform they have gotten all data from the tarpipe
|
||||||
|
time.Sleep(time.Duration(900 * time.Millisecond)) // Let rcvr set this on setup?
|
||||||
|
|
||||||
|
// Clear current op so user can enter next, or EOF
|
||||||
|
rec.SetOp([]byte{0})
|
||||||
|
hc.SetStatus(xsnet.CSOType(cmdStatus))
|
||||||
|
//fmt.Println("Waiting for EOF from other end.")
|
||||||
|
//_, _ = hc.Read(nil /*ackByte*/)
|
||||||
|
//fmt.Println("Got remote end ack.")
|
||||||
|
} else {
|
||||||
|
logger.LogErr(fmt.Sprintln("[Bad xs.Session]")) // nolint: gosec,errcheck
|
||||||
|
}
|
||||||
|
return
|
||||||
|
}(&conn) // nolint: errcheck
|
||||||
|
} // algs valid and not blacklisted
|
||||||
} // Accept() success
|
} // Accept() success
|
||||||
} //endfor
|
} //endfor
|
||||||
//logger.LogNotice(fmt.Sprintln("[Exiting]")) // nolint: gosec,errcheck
|
//logger.LogNotice(fmt.Sprintln("[Exiting]")) // nolint: gosec,errcheck
|
||||||
|
|
19
xsnet/net.go
19
xsnet/net.go
|
@ -25,6 +25,7 @@ package xsnet
|
||||||
import (
|
import (
|
||||||
"bytes"
|
"bytes"
|
||||||
"crypto/cipher"
|
"crypto/cipher"
|
||||||
|
crand "crypto/rand"
|
||||||
"encoding/binary"
|
"encoding/binary"
|
||||||
"encoding/hex"
|
"encoding/hex"
|
||||||
"errors"
|
"errors"
|
||||||
|
@ -39,7 +40,6 @@ import (
|
||||||
"strings"
|
"strings"
|
||||||
"sync"
|
"sync"
|
||||||
"time"
|
"time"
|
||||||
crand "crypto/rand"
|
|
||||||
|
|
||||||
hkex "blitter.com/go/herradurakex"
|
hkex "blitter.com/go/herradurakex"
|
||||||
"blitter.com/go/kyber"
|
"blitter.com/go/kyber"
|
||||||
|
@ -169,11 +169,11 @@ func (hc *Conn) HAlg() CSHmacAlg {
|
||||||
}
|
}
|
||||||
|
|
||||||
func (h *CSHmacAlg) String() string {
|
func (h *CSHmacAlg) String() string {
|
||||||
switch (*h >> 8) & 0x0FF {
|
switch *h & 0x0FF {
|
||||||
case HmacSHA256:
|
case HmacSHA256:
|
||||||
return "H_SHA256"
|
return "H_SHA256"
|
||||||
case HmacSHA512:
|
case HmacSHA512:
|
||||||
return "C_SHA512"
|
return "H_SHA512"
|
||||||
default:
|
default:
|
||||||
return "H_ERR_UNK"
|
return "H_ERR_UNK"
|
||||||
}
|
}
|
||||||
|
@ -296,7 +296,7 @@ func _new(kexAlg KEXAlg, conn *net.Conn) (hc *Conn, e error) {
|
||||||
case KEX_FRODOKEM_976AES:
|
case KEX_FRODOKEM_976AES:
|
||||||
fallthrough
|
fallthrough
|
||||||
case KEX_FRODOKEM_976SHAKE:
|
case KEX_FRODOKEM_976SHAKE:
|
||||||
log.Printf("[KEx alg %d accepted]\n", kexAlg)
|
//log.Printf("[KEx alg %d is valid]\n", kexAlg)
|
||||||
default:
|
default:
|
||||||
// UNREACHABLE: _getkexalgnum() guarantees a valid KEX value
|
// UNREACHABLE: _getkexalgnum() guarantees a valid KEX value
|
||||||
hc.kex = KEX_HERRADURA512
|
hc.kex = KEX_HERRADURA512
|
||||||
|
@ -517,7 +517,7 @@ func NewHopeDialSetup(c io.ReadWriter, hc *Conn) (err error) {
|
||||||
if err != nil {
|
if err != nil {
|
||||||
panic(err)
|
panic(err)
|
||||||
}
|
}
|
||||||
|
|
||||||
hc.r, hc.rm, err = hc.getStream(aliceSharedSecret)
|
hc.r, hc.rm, err = hc.getStream(aliceSharedSecret)
|
||||||
hc.w, hc.wm, err = hc.getStream(aliceSharedSecret)
|
hc.w, hc.wm, err = hc.getStream(aliceSharedSecret)
|
||||||
return
|
return
|
||||||
|
@ -559,7 +559,7 @@ func NewHopeSimpleDialSetup(c io.ReadWriter, hc *Conn) (err error) {
|
||||||
if err != nil {
|
if err != nil {
|
||||||
panic(err)
|
panic(err)
|
||||||
}
|
}
|
||||||
|
|
||||||
hc.r, hc.rm, err = hc.getStream(aliceSharedSecret)
|
hc.r, hc.rm, err = hc.getStream(aliceSharedSecret)
|
||||||
hc.w, hc.wm, err = hc.getStream(aliceSharedSecret)
|
hc.w, hc.wm, err = hc.getStream(aliceSharedSecret)
|
||||||
return
|
return
|
||||||
|
@ -672,7 +672,6 @@ func FrodoKEMAcceptSetup(c *net.Conn, hc *Conn) (err error) {
|
||||||
}
|
}
|
||||||
pubB, secB := kem.Keygen()
|
pubB, secB := kem.Keygen()
|
||||||
|
|
||||||
|
|
||||||
// [Alice sends use a public key (na, ea)
|
// [Alice sends use a public key (na, ea)
|
||||||
pubA_bigint := big.NewInt(0)
|
pubA_bigint := big.NewInt(0)
|
||||||
_, err = fmt.Fscanf(*c, "0x%x\n", pubA_bigint)
|
_, err = fmt.Fscanf(*c, "0x%x\n", pubA_bigint)
|
||||||
|
@ -696,7 +695,7 @@ func FrodoKEMAcceptSetup(c *net.Conn, hc *Conn) (err error) {
|
||||||
|
|
||||||
// (... and send cipher, connection opts)
|
// (... and send cipher, connection opts)
|
||||||
fmt.Fprintf(*c, "0x%x:0x%x\n", hc.cipheropts, hc.opts)
|
fmt.Fprintf(*c, "0x%x:0x%x\n", hc.cipheropts, hc.opts)
|
||||||
|
|
||||||
// Bob, step 3: Create ctBtoA, shareB
|
// Bob, step 3: Create ctBtoA, shareB
|
||||||
ctBtoA, shareB, err := kem.Encapsulate(pubA)
|
ctBtoA, shareB, err := kem.Encapsulate(pubA)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
@ -1173,10 +1172,8 @@ func (hl *HKExListener) Accept() (hc Conn, err error) {
|
||||||
return Conn{}, err
|
return Conn{}, err
|
||||||
}
|
}
|
||||||
|
|
||||||
// Finally, ensure alg proposed by client is allowed by server config
|
|
||||||
//if hc.kex.String() {
|
|
||||||
log.Println("[hc.Accept successful]")
|
log.Println("[hc.Accept successful]")
|
||||||
return
|
return hc, err
|
||||||
}
|
}
|
||||||
|
|
||||||
/*---------------------------------------------------------------------*/
|
/*---------------------------------------------------------------------*/
|
||||||
|
|
Loading…
Reference in New Issue