mirror of
https://gogs.blitter.com/RLabs/xs
synced 2024-08-14 10:26:42 +00:00
Gometalinter cleanup/audit of hkexsh, hkexshd, hkexpasswd
Signed-off-by: Russ Magee <rmagee@gmail.com>
This commit is contained in:
parent
fa398159e3
commit
6fbbcdadb6
14 changed files with 269 additions and 150 deletions
9
Makefile
9
Makefile
|
@ -1,4 +1,4 @@
|
||||||
.PHONY: vis clean common client server passwd subpkgs install uninstall
|
.PHONY: lint vis clean common client server passwd subpkgs install uninstall reinstall
|
||||||
|
|
||||||
SUBPKGS = logger spinsult hkexnet herradurakex
|
SUBPKGS = logger spinsult hkexnet herradurakex
|
||||||
TOOLS = hkexpasswd hkexsh hkexshd
|
TOOLS = hkexpasswd hkexsh hkexshd
|
||||||
|
@ -59,6 +59,13 @@ vis:
|
||||||
make -C hkexpasswd vis; \
|
make -C hkexpasswd vis; \
|
||||||
fi
|
fi
|
||||||
|
|
||||||
|
lint:
|
||||||
|
make -C hkexpasswd lint
|
||||||
|
make -C hkexshd lint
|
||||||
|
make -C hkexsh lint
|
||||||
|
|
||||||
|
reinstall: uninstall install
|
||||||
|
|
||||||
install:
|
install:
|
||||||
cp hkexsh/hkexsh $(INSTPREFIX)/bin
|
cp hkexsh/hkexsh $(INSTPREFIX)/bin
|
||||||
ifeq ($(MSYSTEM),)
|
ifeq ($(MSYSTEM),)
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
// Common constants for the HKExSh
|
// Package hkexsh - common constants for the HKExSh
|
||||||
//
|
//
|
||||||
// Copyright (c) 2017-2018 Russell Magee
|
// Copyright (c) 2017-2018 Russell Magee
|
||||||
// Licensed under the terms of the MIT license (see LICENSE.mit in this
|
// Licensed under the terms of the MIT license (see LICENSE.mit in this
|
||||||
|
@ -7,5 +7,6 @@
|
||||||
// golang implementation by Russ Magee (rmagee_at_gmail.com)
|
// golang implementation by Russ Magee (rmagee_at_gmail.com)
|
||||||
package hkexsh
|
package hkexsh
|
||||||
|
|
||||||
|
// Version string returned by tools
|
||||||
const Version = "0.7pre (NO WARRANTY)"
|
const Version = "0.7pre (NO WARRANTY)"
|
||||||
|
|
||||||
|
|
26
hkexauth.go
26
hkexauth.go
|
@ -24,15 +24,15 @@ import (
|
||||||
|
|
||||||
func userExistsOnSystem(who string) bool {
|
func userExistsOnSystem(who string) bool {
|
||||||
_, userErr := user.Lookup(who)
|
_, userErr := user.Lookup(who)
|
||||||
if userErr != nil {
|
return userErr == nil
|
||||||
return false
|
|
||||||
} else {
|
|
||||||
return true
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// AuthUserByPasswd checks user login information using a password.
|
||||||
|
// This checks /etc/hkexsh.passwd for auth info, and system /etc/passwd
|
||||||
|
// to cross-check the user actually exists.
|
||||||
|
// nolint: gocyclo
|
||||||
func AuthUserByPasswd(username string, auth string, fname string) (valid bool, allowedCmds string) {
|
func AuthUserByPasswd(username string, auth string, fname string) (valid bool, allowedCmds string) {
|
||||||
b, e := ioutil.ReadFile(fname)
|
b, e := ioutil.ReadFile(fname) // nolint: gosec
|
||||||
if e != nil {
|
if e != nil {
|
||||||
valid = false
|
valid = false
|
||||||
log.Println("ERROR: Cannot read hkexsh.passwd file!")
|
log.Println("ERROR: Cannot read hkexsh.passwd file!")
|
||||||
|
@ -60,7 +60,10 @@ func AuthUserByPasswd(username string, auth string, fname string) (valid bool, a
|
||||||
}
|
}
|
||||||
|
|
||||||
if username == record[0] {
|
if username == record[0] {
|
||||||
tmp, _ := bcrypt.Hash(auth, record[1])
|
tmp, err := bcrypt.Hash(auth, record[1])
|
||||||
|
if err != nil {
|
||||||
|
break
|
||||||
|
}
|
||||||
if tmp == record[2] && username != "$nosuchuser$" {
|
if tmp == record[2] && username != "$nosuchuser$" {
|
||||||
valid = true
|
valid = true
|
||||||
}
|
}
|
||||||
|
@ -71,7 +74,6 @@ func AuthUserByPasswd(username string, auth string, fname string) (valid bool, a
|
||||||
for i := range b {
|
for i := range b {
|
||||||
b[i] = 0
|
b[i] = 0
|
||||||
}
|
}
|
||||||
b = nil
|
|
||||||
r = nil
|
r = nil
|
||||||
runtime.GC()
|
runtime.GC()
|
||||||
|
|
||||||
|
@ -81,6 +83,11 @@ func AuthUserByPasswd(username string, auth string, fname string) (valid bool, a
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// AuthUserByToken checks user login information against an auth token.
|
||||||
|
// Auth tokens are stored in each user's $HOME/.hkexsh_id and are requested
|
||||||
|
// via the -g option.
|
||||||
|
// The function also check system /etc/passwd to cross-check the user
|
||||||
|
// actually exists.
|
||||||
func AuthUserByToken(username string, connhostname string, auth string) (valid bool) {
|
func AuthUserByToken(username string, connhostname string, auth string) (valid bool) {
|
||||||
auth = strings.TrimSpace(auth)
|
auth = strings.TrimSpace(auth)
|
||||||
u, ue := user.Lookup(username)
|
u, ue := user.Lookup(username)
|
||||||
|
@ -111,7 +118,8 @@ func AuthUserByToken(username string, connhostname string, auth string) (valid b
|
||||||
|
|
||||||
if (connhostname == record[0]) &&
|
if (connhostname == record[0]) &&
|
||||||
(auth == strings.Join([]string{record[0], record[1]}, ":")) {
|
(auth == strings.Join([]string{record[0], record[1]}, ":")) {
|
||||||
return true
|
valid = true
|
||||||
|
break
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if !userExistsOnSystem(username) {
|
if !userExistsOnSystem(username) {
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
.PHONY: clean all vis
|
.PHONY: clean all vis lint
|
||||||
|
|
||||||
EXTPKGS = bytes,errors,flag,fmt,internal,io,log,net,os,path,runtime,time,strings,sync,syscall,binary,encoding
|
EXTPKGS = bytes,errors,flag,fmt,internal,io,log,net,os,path,runtime,time,strings,sync,syscall,binary,encoding
|
||||||
EXE = $(notdir $(shell pwd))
|
EXE = $(notdir $(shell pwd))
|
||||||
|
@ -12,3 +12,5 @@ clean:
|
||||||
vis:
|
vis:
|
||||||
go-callvis -skipbrowser -png -svg -output hkexpasswd-vis -ignore $(EXTPKGS) -group pkg,type .
|
go-callvis -skipbrowser -png -svg -output hkexpasswd-vis -ignore $(EXTPKGS) -group pkg,type .
|
||||||
|
|
||||||
|
lint:
|
||||||
|
-gometalinter --deadline=60s | sort
|
||||||
|
|
|
@ -21,6 +21,7 @@ import (
|
||||||
"github.com/jameskeane/bcrypt"
|
"github.com/jameskeane/bcrypt"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
// nolint: gocyclo
|
||||||
func main() {
|
func main() {
|
||||||
var pfName string
|
var pfName string
|
||||||
var newpw string
|
var newpw string
|
||||||
|
@ -84,7 +85,7 @@ func main() {
|
||||||
}
|
}
|
||||||
//fmt.Println("Salt:", salt, "Hash:", hash)
|
//fmt.Println("Salt:", salt, "Hash:", hash)
|
||||||
|
|
||||||
b, err := ioutil.ReadFile(pfName)
|
b, err := ioutil.ReadFile(pfName) // nolint: gosec
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Fatal(err)
|
log.Fatal(err)
|
||||||
}
|
}
|
||||||
|
@ -100,7 +101,7 @@ func main() {
|
||||||
}
|
}
|
||||||
|
|
||||||
recFound := false
|
recFound := false
|
||||||
for i, _ := range records {
|
for i := range records {
|
||||||
//fmt.Println(records[i])
|
//fmt.Println(records[i])
|
||||||
if records[i][0] == uname {
|
if records[i][0] == uname {
|
||||||
recFound = true
|
recFound = true
|
||||||
|
@ -124,8 +125,14 @@ func main() {
|
||||||
w := csv.NewWriter(outFile)
|
w := csv.NewWriter(outFile)
|
||||||
w.Comma = ':'
|
w.Comma = ':'
|
||||||
//w.FieldsPerRecord = 4 // username:salt:authCookie:disallowedCmdList (a,b,...)
|
//w.FieldsPerRecord = 4 // username:salt:authCookie:disallowedCmdList (a,b,...)
|
||||||
w.Write([]string{"#username", "salt", "authCookie"/*, "disallowedCmdList"*/})
|
err = w.Write([]string{"#username", "salt", "authCookie" /*, "disallowedCmdList"*/})
|
||||||
w.WriteAll(records)
|
if err != nil {
|
||||||
|
log.Fatal(err)
|
||||||
|
}
|
||||||
|
err = w.WriteAll(records)
|
||||||
|
if err != nil {
|
||||||
|
log.Fatal(err)
|
||||||
|
}
|
||||||
if err = w.Error(); err != nil {
|
if err = w.Error(); err != nil {
|
||||||
log.Fatal(err)
|
log.Fatal(err)
|
||||||
}
|
}
|
||||||
|
|
|
@ -13,6 +13,7 @@ import (
|
||||||
"runtime"
|
"runtime"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
// Session holds essential bookkeeping info about an active session.
|
||||||
type Session struct {
|
type Session struct {
|
||||||
op []byte
|
op []byte
|
||||||
who []byte
|
who []byte
|
||||||
|
@ -29,58 +30,80 @@ func (h *Session) String() string {
|
||||||
h.op, h.who, h.cmd, h.AuthCookie(false), h.status)
|
h.op, h.who, h.cmd, h.AuthCookie(false), h.status)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Op returns the op code of the Session (interactive shell, cmd, ...)
|
||||||
func (h Session) Op() []byte {
|
func (h Session) Op() []byte {
|
||||||
return h.op
|
return h.op
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// SetOp stores the op code desired for a Session.
|
||||||
func (h *Session) SetOp(o []byte) {
|
func (h *Session) SetOp(o []byte) {
|
||||||
h.op = o
|
h.op = o
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Who returns the user associated with a Session.
|
||||||
func (h Session) Who() []byte {
|
func (h Session) Who() []byte {
|
||||||
return h.who
|
return h.who
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// SetWho sets the username associated with a Session.
|
||||||
func (h *Session) SetWho(w []byte) {
|
func (h *Session) SetWho(w []byte) {
|
||||||
h.who = w
|
h.who = w
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// ConnHost returns the connecting hostname/IP string for a Session.
|
||||||
func (h Session) ConnHost() []byte {
|
func (h Session) ConnHost() []byte {
|
||||||
return h.connhost
|
return h.connhost
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// SetConnHost stores the connecting hostname/IP string for a Session.
|
||||||
func (h *Session) SetConnHost(n []byte) {
|
func (h *Session) SetConnHost(n []byte) {
|
||||||
h.connhost = n
|
h.connhost = n
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// TermType returns the TERM env variable reported by the client initiating
|
||||||
|
// a Session.
|
||||||
func (h Session) TermType() []byte {
|
func (h Session) TermType() []byte {
|
||||||
return h.termtype
|
return h.termtype
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// SetTermType stores the TERM env variable supplied by the client initiating
|
||||||
|
// a Session.
|
||||||
func (h *Session) SetTermType(t []byte) {
|
func (h *Session) SetTermType(t []byte) {
|
||||||
h.termtype = t
|
h.termtype = t
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Cmd returns the command requested for execution by a client initiating
|
||||||
|
// the Session.
|
||||||
func (h Session) Cmd() []byte {
|
func (h Session) Cmd() []byte {
|
||||||
return h.cmd
|
return h.cmd
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// SetCmd stores the command request by the client for execution when initiating
|
||||||
|
// the Session.
|
||||||
func (h *Session) SetCmd(c []byte) {
|
func (h *Session) SetCmd(c []byte) {
|
||||||
h.cmd = c
|
h.cmd = c
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// AuthCookie returns the authcookie (essentially the password) used for
|
||||||
|
// authorization of the Session. This return value is censored unless
|
||||||
|
// reallyShow is true (so dumps of Session Info do not accidentally leak it).
|
||||||
func (h Session) AuthCookie(reallyShow bool) []byte {
|
func (h Session) AuthCookie(reallyShow bool) []byte {
|
||||||
if reallyShow {
|
if reallyShow {
|
||||||
return h.authCookie
|
return h.authCookie
|
||||||
} else {
|
|
||||||
return []byte("**REDACTED**")
|
|
||||||
}
|
}
|
||||||
|
return []byte("**REDACTED**")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// SetAuthCookie stores the authcookie (essential the password) used to
|
||||||
|
// authenticate the Session.
|
||||||
func (h *Session) SetAuthCookie(a []byte) {
|
func (h *Session) SetAuthCookie(a []byte) {
|
||||||
h.authCookie = a
|
h.authCookie = a
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// ClearAuthCookie attempts to scrub the Session's stored authcookie.
|
||||||
|
//
|
||||||
|
// This should of course be called as soon as possible after authentication
|
||||||
|
// and it is no longer required.
|
||||||
func (h *Session) ClearAuthCookie() {
|
func (h *Session) ClearAuthCookie() {
|
||||||
for i := range h.authCookie {
|
for i := range h.authCookie {
|
||||||
h.authCookie[i] = 0
|
h.authCookie[i] = 0
|
||||||
|
@ -88,14 +111,20 @@ func (h *Session) ClearAuthCookie() {
|
||||||
runtime.GC()
|
runtime.GC()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Status returns the (current) Session status code.
|
||||||
|
//
|
||||||
|
// This usually corresponds to a UNIX shell exit code, but
|
||||||
|
// extended codes are returns at times to indicate internal errors.
|
||||||
func (h Session) Status() uint32 {
|
func (h Session) Status() uint32 {
|
||||||
return h.status
|
return h.status
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// SetStatus stores the current Session status code.
|
||||||
func (h *Session) SetStatus(s uint32) {
|
func (h *Session) SetStatus(s uint32) {
|
||||||
h.status = s
|
h.status = s
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// NewSession returns a new Session record.
|
||||||
func NewSession(op, who, connhost, ttype, cmd, authcookie []byte, status uint32) *Session {
|
func NewSession(op, who, connhost, ttype, cmd, authcookie []byte, status uint32) *Session {
|
||||||
return &Session{
|
return &Session{
|
||||||
op: op,
|
op: op,
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
.PHONY: clean all vis
|
.PHONY: clean all vis lint
|
||||||
|
|
||||||
EXTPKGS = bytes,errors,flag,fmt,internal,io,log,net,os,path,runtime,time,strings,sync,syscall,binary,encoding
|
EXTPKGS = bytes,errors,flag,fmt,internal,io,log,net,os,path,runtime,time,strings,sync,syscall,binary,encoding
|
||||||
EXE = $(notdir $(shell pwd))
|
EXE = $(notdir $(shell pwd))
|
||||||
|
@ -12,4 +12,6 @@ clean:
|
||||||
vis:
|
vis:
|
||||||
go-callvis -skipbrowser -svg -png -output hkexsh-vis -ignore $(EXTPKGS) -group pkg,type .
|
go-callvis -skipbrowser -svg -png -output hkexsh-vis -ignore $(EXTPKGS) -group pkg,type .
|
||||||
|
|
||||||
|
lint:
|
||||||
|
-gometalinter --deadline=60s | sort
|
||||||
|
|
||||||
|
|
|
@ -66,6 +66,7 @@ func GetSize() (cols, rows int, err error) {
|
||||||
}
|
}
|
||||||
|
|
||||||
// doCopyMode begins a secure hkexsh local<->remote file copy operation.
|
// doCopyMode begins a secure hkexsh local<->remote file copy operation.
|
||||||
|
// TODO: reduce gocyclo
|
||||||
func doCopyMode(conn *hkexnet.Conn, remoteDest bool, files string, rec *hkexsh.Session) (exitStatus uint32, err error) {
|
func doCopyMode(conn *hkexnet.Conn, remoteDest bool, files string, rec *hkexsh.Session) (exitStatus uint32, err error) {
|
||||||
if remoteDest {
|
if remoteDest {
|
||||||
log.Println("local files:", files, "remote filepath:", string(rec.Cmd()))
|
log.Println("local files:", files, "remote filepath:", string(rec.Cmd()))
|
||||||
|
@ -299,15 +300,15 @@ func doShellMode(isInteractive bool, conn *hkexnet.Conn, oldState *hkexsh.State,
|
||||||
}
|
}
|
||||||
|
|
||||||
func usageShell() {
|
func usageShell() {
|
||||||
fmt.Fprintf(os.Stderr, "Usage of %s:\n", os.Args[0])
|
fmt.Fprintf(os.Stderr, "Usage of %s:\n", os.Args[0]) // nolint: errcheck
|
||||||
fmt.Fprintf(os.Stderr, "%s [opts] [user]@server\n", os.Args[0])
|
fmt.Fprintf(os.Stderr, "%s [opts] [user]@server\n", os.Args[0]) // nolint: errcheck
|
||||||
flag.PrintDefaults()
|
flag.PrintDefaults()
|
||||||
}
|
}
|
||||||
|
|
||||||
func usageCp() {
|
func usageCp() {
|
||||||
fmt.Fprintf(os.Stderr, "Usage of %s:\n", os.Args[0])
|
fmt.Fprintf(os.Stderr, "Usage of %s:\n", os.Args[0]) // nolint: errcheck
|
||||||
fmt.Fprintf(os.Stderr, "%s [opts] srcFileOrDir [...] [user]@server[:dstpath]\n", os.Args[0])
|
fmt.Fprintf(os.Stderr, "%s [opts] srcFileOrDir [...] [user]@server[:dstpath]\n", os.Args[0]) // nolint: errcheck
|
||||||
fmt.Fprintf(os.Stderr, "%s [opts] [user]@server[:srcFileOrDir] dstPath\n", os.Args[0])
|
fmt.Fprintf(os.Stderr, "%s [opts] [user]@server[:srcFileOrDir] dstPath\n", os.Args[0]) // nolint: errcheck
|
||||||
flag.PrintDefaults()
|
flag.PrintDefaults()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -323,17 +324,15 @@ func reqTunnel(hc *hkexnet.Conn, lp uint16, p string /*net.Addr*/, rp uint16) {
|
||||||
// Write request to server so it can attempt to set up its end
|
// Write request to server so it can attempt to set up its end
|
||||||
var bTmp bytes.Buffer
|
var bTmp bytes.Buffer
|
||||||
if e := binary.Write(&bTmp, binary.BigEndian, lp); e != nil {
|
if e := binary.Write(&bTmp, binary.BigEndian, lp); e != nil {
|
||||||
fmt.Fprintln(os.Stderr, "reqTunnel:", e)
|
fmt.Fprintln(os.Stderr, "reqTunnel:", e) // nolint: errcheck
|
||||||
}
|
}
|
||||||
if e := binary.Write(&bTmp, binary.BigEndian, rp); e != nil {
|
if e := binary.Write(&bTmp, binary.BigEndian, rp); e != nil {
|
||||||
fmt.Fprintln(os.Stderr, "reqTunnel:", e)
|
fmt.Fprintln(os.Stderr, "reqTunnel:", e) // nolint: errcheck
|
||||||
}
|
}
|
||||||
_ = logger.LogDebug(fmt.Sprintln("[Client sending CSOTunSetup]"))
|
_ = logger.LogDebug(fmt.Sprintln("[Client sending CSOTunSetup]")) // nolint: gosec
|
||||||
if n, e := hc.WritePacket(bTmp.Bytes(), hkexnet.CSOTunSetup); e != nil || n != len(bTmp.Bytes()) {
|
if n, e := hc.WritePacket(bTmp.Bytes(), hkexnet.CSOTunSetup); e != nil || n != len(bTmp.Bytes()) {
|
||||||
fmt.Fprintln(os.Stderr, "reqTunnel:", e)
|
fmt.Fprintln(os.Stderr, "reqTunnel:", e) // nolint: errcheck
|
||||||
}
|
}
|
||||||
|
|
||||||
return
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func parseNonSwitchArgs(a []string) (user, host, path string, isDest bool, otherArgs []string) {
|
func parseNonSwitchArgs(a []string) (user, host, path string, isDest bool, otherArgs []string) {
|
||||||
|
@ -378,7 +377,7 @@ func parseNonSwitchArgs(a []string) (user, host, path string, isDest bool, other
|
||||||
}
|
}
|
||||||
|
|
||||||
func launchTuns(conn *hkexnet.Conn, remoteHost string, tuns string) {
|
func launchTuns(conn *hkexnet.Conn, remoteHost string, tuns string) {
|
||||||
remAddrs, _ := net.LookupHost(remoteHost)
|
remAddrs, _ := net.LookupHost(remoteHost) // nolint: gosec
|
||||||
|
|
||||||
if tuns == "" {
|
if tuns == "" {
|
||||||
return
|
return
|
||||||
|
@ -387,7 +386,7 @@ func launchTuns(conn *hkexnet.Conn, remoteHost string, tuns string) {
|
||||||
tunSpecs := strings.Split(tuns, ",")
|
tunSpecs := strings.Split(tuns, ",")
|
||||||
for _, tunItem := range tunSpecs {
|
for _, tunItem := range tunSpecs {
|
||||||
var lPort, rPort uint16
|
var lPort, rPort uint16
|
||||||
_, _ = fmt.Sscanf(tunItem, "%d:%d", &lPort, &rPort)
|
_, _ = fmt.Sscanf(tunItem, "%d:%d", &lPort, &rPort) // nolint: gosec
|
||||||
reqTunnel(conn, lPort, remAddrs[0], rPort)
|
reqTunnel(conn, lPort, remAddrs[0], rPort)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -395,13 +394,31 @@ func launchTuns(conn *hkexnet.Conn, remoteHost string, tuns string) {
|
||||||
func sendSessionParams(conn io.Writer /* *hkexnet.Conn*/, rec *hkexsh.Session) (e error) {
|
func sendSessionParams(conn io.Writer /* *hkexnet.Conn*/, rec *hkexsh.Session) (e error) {
|
||||||
_, e = fmt.Fprintf(conn, "%d %d %d %d %d %d\n",
|
_, e = fmt.Fprintf(conn, "%d %d %d %d %d %d\n",
|
||||||
len(rec.Op()), len(rec.Who()), len(rec.ConnHost()), len(rec.TermType()), len(rec.Cmd()), len(rec.AuthCookie(true)))
|
len(rec.Op()), len(rec.Who()), len(rec.ConnHost()), len(rec.TermType()), len(rec.Cmd()), len(rec.AuthCookie(true)))
|
||||||
|
if e != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
_, e = conn.Write(rec.Op())
|
_, e = conn.Write(rec.Op())
|
||||||
|
if e != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
_, e = conn.Write(rec.Who())
|
_, e = conn.Write(rec.Who())
|
||||||
|
if e != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
_, e = conn.Write(rec.ConnHost())
|
_, e = conn.Write(rec.ConnHost())
|
||||||
|
if e != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
_, e = conn.Write(rec.TermType())
|
_, e = conn.Write(rec.TermType())
|
||||||
|
if e != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
_, e = conn.Write(rec.Cmd())
|
_, e = conn.Write(rec.Cmd())
|
||||||
|
if e != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
_, e = conn.Write(rec.AuthCookie(true))
|
_, e = conn.Write(rec.AuthCookie(true))
|
||||||
return
|
return e
|
||||||
}
|
}
|
||||||
|
|
||||||
// hkexsh - a client for secure shell and file copy operations.
|
// hkexsh - a client for secure shell and file copy operations.
|
||||||
|
@ -415,6 +432,7 @@ func sendSessionParams(conn io.Writer /* *hkexnet.Conn*/, rec *hkexsh.Session) (
|
||||||
// setting desired; as well as the intended operation mode for the
|
// setting desired; as well as the intended operation mode for the
|
||||||
// connection (app-specific, passed through to the server to use or
|
// connection (app-specific, passed through to the server to use or
|
||||||
// ignore at its discretion).
|
// ignore at its discretion).
|
||||||
|
// TODO: reduce gocyclo
|
||||||
func main() {
|
func main() {
|
||||||
version := hkexsh.Version
|
version := hkexsh.Version
|
||||||
var vopt bool
|
var vopt bool
|
||||||
|
@ -475,7 +493,7 @@ func main() {
|
||||||
// Set defaults if user doesn't specify user, path or port
|
// Set defaults if user doesn't specify user, path or port
|
||||||
var uname string
|
var uname string
|
||||||
if remoteUser == "" {
|
if remoteUser == "" {
|
||||||
u, _ := user.Current()
|
u, _ := user.Current() // nolint: gosec
|
||||||
uname = u.Username
|
uname = u.Username
|
||||||
} else {
|
} else {
|
||||||
uname = remoteUser
|
uname = remoteUser
|
||||||
|
@ -541,7 +559,7 @@ func main() {
|
||||||
// either the shell session or copy operation.
|
// either the shell session or copy operation.
|
||||||
_ = shellMode
|
_ = shellMode
|
||||||
|
|
||||||
Log, _ = logger.New(logger.LOG_USER|logger.LOG_DEBUG|logger.LOG_NOTICE|logger.LOG_ERR, "hkexsh")
|
Log, _ = logger.New(logger.LOG_USER|logger.LOG_DEBUG|logger.LOG_NOTICE|logger.LOG_ERR, "hkexsh") // nolint: errcheck,gosec
|
||||||
hkexnet.Init(dbg, "hkexsh", logger.LOG_USER|logger.LOG_DEBUG|logger.LOG_NOTICE|logger.LOG_ERR)
|
hkexnet.Init(dbg, "hkexsh", logger.LOG_USER|logger.LOG_DEBUG|logger.LOG_NOTICE|logger.LOG_ERR)
|
||||||
if dbg {
|
if dbg {
|
||||||
log.SetOutput(Log)
|
log.SetOutput(Log)
|
||||||
|
@ -551,7 +569,7 @@ func main() {
|
||||||
|
|
||||||
if !gopt {
|
if !gopt {
|
||||||
// See if we can log in via an auth token
|
// See if we can log in via an auth token
|
||||||
u, _ := user.Current()
|
u, _ := user.Current() // nolint: gosec
|
||||||
ab, aerr := ioutil.ReadFile(fmt.Sprintf("%s/.hkexsh_id", u.HomeDir))
|
ab, aerr := ioutil.ReadFile(fmt.Sprintf("%s/.hkexsh_id", u.HomeDir))
|
||||||
if aerr == nil {
|
if aerr == nil {
|
||||||
idx := strings.Index(string(ab), remoteHost)
|
idx := strings.Index(string(ab), remoteHost)
|
||||||
|
@ -574,7 +592,7 @@ func main() {
|
||||||
// We must make the decision about interactivity before Dial()
|
// We must make the decision about interactivity before Dial()
|
||||||
// as it affects chaffing behaviour. 20180805
|
// as it affects chaffing behaviour. 20180805
|
||||||
if gopt {
|
if gopt {
|
||||||
fmt.Fprintln(os.Stderr, "[requesting authtoken from server]")
|
fmt.Fprintln(os.Stderr, "[requesting authtoken from server]") // nolint: errcheck
|
||||||
op = []byte{'A'}
|
op = []byte{'A'}
|
||||||
chaffFreqMin = 2
|
chaffFreqMin = 2
|
||||||
chaffFreqMax = 10
|
chaffFreqMax = 10
|
||||||
|
@ -615,7 +633,7 @@ func main() {
|
||||||
fmt.Println(err)
|
fmt.Println(err)
|
||||||
panic(err)
|
panic(err)
|
||||||
}
|
}
|
||||||
defer conn.Close()
|
defer conn.Close() // nolint: errcheck
|
||||||
// From this point on, conn is a secure encrypted channel
|
// From this point on, conn is a secure encrypted channel
|
||||||
|
|
||||||
// Set stdin in raw mode if it's an interactive session
|
// Set stdin in raw mode if it's an interactive session
|
||||||
|
@ -628,7 +646,7 @@ func main() {
|
||||||
if err != nil {
|
if err != nil {
|
||||||
panic(err)
|
panic(err)
|
||||||
}
|
}
|
||||||
defer func() { _ = hkexsh.Restore(int(os.Stdin.Fd()), oldState) }() // Best effort.
|
defer func() { _ = hkexsh.Restore(int(os.Stdin.Fd()), oldState) }() // nolint: errcheck,gosec
|
||||||
} else {
|
} else {
|
||||||
log.Println("NOT A TTY")
|
log.Println("NOT A TTY")
|
||||||
}
|
}
|
||||||
|
@ -649,20 +667,23 @@ func main() {
|
||||||
|
|
||||||
// Set up session params and send over to server
|
// Set up session params and send over to server
|
||||||
rec := hkexsh.NewSession(op, []byte(uname), []byte(remoteHost), []byte(os.Getenv("TERM")), []byte(cmdStr), []byte(authCookie), 0)
|
rec := hkexsh.NewSession(op, []byte(uname), []byte(remoteHost), []byte(os.Getenv("TERM")), []byte(cmdStr), []byte(authCookie), 0)
|
||||||
sendSessionParams(&conn, rec)
|
sendErr := sendSessionParams(&conn, rec)
|
||||||
|
if sendErr != nil {
|
||||||
|
log.Fatal(sendErr)
|
||||||
|
}
|
||||||
|
|
||||||
//Security scrub
|
//Security scrub
|
||||||
authCookie = ""
|
authCookie = "" // nolint: ineffassign
|
||||||
runtime.GC()
|
runtime.GC()
|
||||||
|
|
||||||
// Read auth reply from server
|
// Read auth reply from server
|
||||||
authReply := make([]byte, 1) // bool: 0 = fail, 1 = pass
|
authReply := make([]byte, 1) // bool: 0 = fail, 1 = pass
|
||||||
_, err = conn.Read(authReply)
|
_, err = conn.Read(authReply)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
fmt.Fprintln(os.Stderr, "Error reading auth reply")
|
fmt.Fprintln(os.Stderr, "Error reading auth reply") // nolint: errcheck
|
||||||
rec.SetStatus(255)
|
rec.SetStatus(255)
|
||||||
} else if authReply[0] == 0 {
|
} else if authReply[0] == 0 {
|
||||||
fmt.Fprintln(os.Stderr, rejectUserMsg())
|
fmt.Fprintln(os.Stderr, rejectUserMsg()) // nolint: errcheck
|
||||||
rec.SetStatus(255)
|
rec.SetStatus(255)
|
||||||
} else {
|
} else {
|
||||||
|
|
||||||
|
@ -678,7 +699,7 @@ func main() {
|
||||||
go func() {
|
go func() {
|
||||||
for {
|
for {
|
||||||
time.Sleep(time.Duration(2) * time.Second)
|
time.Sleep(time.Duration(2) * time.Second)
|
||||||
conn.WritePacket([]byte{0, 0}, hkexnet.CSOTunKeepAlive)
|
conn.WritePacket([]byte{0, 0}, hkexnet.CSOTunKeepAlive) // nolint: errcheck,gosec
|
||||||
}
|
}
|
||||||
}()
|
}()
|
||||||
|
|
||||||
|
@ -687,17 +708,17 @@ func main() {
|
||||||
|
|
||||||
doShellMode(isInteractive, &conn, oldState, rec)
|
doShellMode(isInteractive, &conn, oldState, rec)
|
||||||
} else { // copyMode
|
} else { // copyMode
|
||||||
s, _ := doCopyMode(&conn, pathIsDest, fileArgs, rec)
|
s, _ := doCopyMode(&conn, pathIsDest, fileArgs, rec) // nolint: errcheck,gosec
|
||||||
rec.SetStatus(s)
|
rec.SetStatus(s)
|
||||||
}
|
}
|
||||||
|
|
||||||
if rec.Status() != 0 {
|
if rec.Status() != 0 {
|
||||||
fmt.Fprintln(os.Stderr, "Session exited with status:", rec.Status())
|
fmt.Fprintln(os.Stderr, "Session exited with status:", rec.Status()) // nolint: errcheck
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if oldState != nil {
|
if oldState != nil {
|
||||||
_ = hkexsh.Restore(int(os.Stdin.Fd()), oldState) // Best effort.
|
_ = hkexsh.Restore(int(os.Stdin.Fd()), oldState) // nolint: gosec
|
||||||
}
|
}
|
||||||
os.Exit(int(rec.Status()))
|
os.Exit(int(rec.Status()))
|
||||||
}
|
}
|
||||||
|
|
|
@ -29,7 +29,7 @@ func handleTermResizes(conn *hkexnet.Conn) {
|
||||||
log.Println(err)
|
log.Println(err)
|
||||||
}
|
}
|
||||||
termSzPacket := fmt.Sprintf("%d %d", rows, cols)
|
termSzPacket := fmt.Sprintf("%d %d", rows, cols)
|
||||||
conn.WritePacket([]byte(termSzPacket), hkexnet.CSOTermSize)
|
conn.WritePacket([]byte(termSzPacket), hkexnet.CSOTermSize) // nolint: errcheck,gosec
|
||||||
}
|
}
|
||||||
}()
|
}()
|
||||||
ch <- syscall.SIGWINCH // Initial resize.
|
ch <- syscall.SIGWINCH // Initial resize.
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
.PHONY: clean all vis
|
.PHONY: clean all vis lint
|
||||||
|
|
||||||
EXTPKGS = binary,bytes,crypto,encoding,errors,flag,fmt,internal,io,log,net,os,path,runtime,time,strings,sync,syscall
|
EXTPKGS = binary,bytes,crypto,encoding,errors,flag,fmt,internal,io,log,net,os,path,runtime,time,strings,sync,syscall
|
||||||
EXE = $(notdir $(shell pwd))
|
EXE = $(notdir $(shell pwd))
|
||||||
|
@ -12,3 +12,6 @@ clean:
|
||||||
vis:
|
vis:
|
||||||
go-callvis -skipbrowser -png -svg -output hkexshd-vis -ignore $(EXTPKGS) -group pkg,type .
|
go-callvis -skipbrowser -png -svg -output hkexshd-vis -ignore $(EXTPKGS) -group pkg,type .
|
||||||
|
|
||||||
|
lint:
|
||||||
|
-gometalinter --deadline=60s | sort
|
||||||
|
|
||||||
|
|
|
@ -34,16 +34,17 @@ import (
|
||||||
)
|
)
|
||||||
|
|
||||||
var (
|
var (
|
||||||
Log *logger.Writer // reg. syslog output (no -d)
|
// Log - syslog output (with no -d)
|
||||||
|
Log *logger.Writer
|
||||||
)
|
)
|
||||||
|
|
||||||
/* -------------------------------------------------------------- */
|
/* -------------------------------------------------------------- */
|
||||||
// Perform a client->server copy
|
// Perform a client->server copy
|
||||||
func runClientToServerCopyAs(who, ttype string, conn *hkexnet.Conn, fpath string, chaffing bool) (err error, exitStatus uint32) {
|
func runClientToServerCopyAs(who, ttype string, conn *hkexnet.Conn, fpath string, chaffing bool) (exitStatus uint32, err error) {
|
||||||
u, _ := user.Lookup(who)
|
u, _ := user.Lookup(who) // nolint: gosec
|
||||||
var uid, gid uint32
|
var uid, gid uint32
|
||||||
fmt.Sscanf(u.Uid, "%d", &uid)
|
fmt.Sscanf(u.Uid, "%d", &uid) // nolint: gosec,errcheck
|
||||||
fmt.Sscanf(u.Gid, "%d", &gid)
|
fmt.Sscanf(u.Gid, "%d", &gid) // nolint: gosec,errcheck
|
||||||
log.Println("uid:", uid, "gid:", gid)
|
log.Println("uid:", uid, "gid:", gid)
|
||||||
|
|
||||||
// Need to clear server's env and set key vars of the
|
// Need to clear server's env and set key vars of the
|
||||||
|
@ -54,9 +55,9 @@ func runClientToServerCopyAs(who, ttype string, conn *hkexnet.Conn, fpath string
|
||||||
// of client shell window used to run client.
|
// of client shell window used to run client.
|
||||||
// Investigate -- rlm 2018-01-26)
|
// Investigate -- rlm 2018-01-26)
|
||||||
os.Clearenv()
|
os.Clearenv()
|
||||||
os.Setenv("HOME", u.HomeDir)
|
os.Setenv("HOME", u.HomeDir) // nolint: gosec,errcheck
|
||||||
os.Setenv("TERM", ttype)
|
os.Setenv("TERM", ttype) // nolint: gosec,errcheck
|
||||||
os.Setenv("HKEXSH", "1")
|
os.Setenv("HKEXSH", "1") // nolint: gosec,errcheck
|
||||||
|
|
||||||
var c *exec.Cmd
|
var c *exec.Cmd
|
||||||
cmdName := "/bin/tar"
|
cmdName := "/bin/tar"
|
||||||
|
@ -74,7 +75,7 @@ func runClientToServerCopyAs(who, ttype string, conn *hkexnet.Conn, fpath string
|
||||||
// When args are passed in exec() format, no quoting is required
|
// When args are passed in exec() format, no quoting is required
|
||||||
// (as this isn't input from a shell) (right? -rlm 20180823)
|
// (as this isn't input from a shell) (right? -rlm 20180823)
|
||||||
//cmdArgs := []string{"-x", "-C", destDir, `--xform=s#.*/\(.*\)#\1#`}
|
//cmdArgs := []string{"-x", "-C", destDir, `--xform=s#.*/\(.*\)#\1#`}
|
||||||
c = exec.Command(cmdName, cmdArgs...)
|
c = exec.Command(cmdName, cmdArgs...) // nolint: gosec
|
||||||
|
|
||||||
c.Dir = destDir
|
c.Dir = destDir
|
||||||
|
|
||||||
|
@ -128,7 +129,7 @@ func runClientToServerCopyAs(who, ttype string, conn *hkexnet.Conn, fpath string
|
||||||
// an ExitStatus() method with the same signature.
|
// an ExitStatus() method with the same signature.
|
||||||
if status, ok := exiterr.Sys().(syscall.WaitStatus); ok {
|
if status, ok := exiterr.Sys().(syscall.WaitStatus); ok {
|
||||||
exitStatus = uint32(status.ExitStatus())
|
exitStatus = uint32(status.ExitStatus())
|
||||||
err = errors.New("cmd returned nonzero status")
|
//err = errors.New("cmd returned nonzero status")
|
||||||
log.Printf("Exit Status: %d\n", exitStatus)
|
log.Printf("Exit Status: %d\n", exitStatus)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -139,11 +140,15 @@ func runClientToServerCopyAs(who, ttype string, conn *hkexnet.Conn, fpath string
|
||||||
}
|
}
|
||||||
|
|
||||||
// Perform a server->client copy
|
// Perform a server->client copy
|
||||||
func runServerToClientCopyAs(who, ttype string, conn *hkexnet.Conn, srcPath string, chaffing bool) (err error, exitStatus uint32) {
|
func runServerToClientCopyAs(who, ttype string, conn *hkexnet.Conn, srcPath string, chaffing bool) (exitStatus uint32, err error) {
|
||||||
u, _ := user.Lookup(who)
|
u, err := user.Lookup(who)
|
||||||
|
if err != nil {
|
||||||
|
exitStatus = 1
|
||||||
|
return
|
||||||
|
}
|
||||||
var uid, gid uint32
|
var uid, gid uint32
|
||||||
fmt.Sscanf(u.Uid, "%d", &uid)
|
_, _ = fmt.Sscanf(u.Uid, "%d", &uid) // nolint: gosec
|
||||||
fmt.Sscanf(u.Gid, "%d", &gid)
|
_, _ = fmt.Sscanf(u.Gid, "%d", &gid) // nolint: gosec
|
||||||
log.Println("uid:", uid, "gid:", gid)
|
log.Println("uid:", uid, "gid:", gid)
|
||||||
|
|
||||||
// Need to clear server's env and set key vars of the
|
// Need to clear server's env and set key vars of the
|
||||||
|
@ -154,9 +159,9 @@ func runServerToClientCopyAs(who, ttype string, conn *hkexnet.Conn, srcPath stri
|
||||||
// of client shell window used to run client.
|
// of client shell window used to run client.
|
||||||
// Investigate -- rlm 2018-01-26)
|
// Investigate -- rlm 2018-01-26)
|
||||||
os.Clearenv()
|
os.Clearenv()
|
||||||
os.Setenv("HOME", u.HomeDir)
|
_ = os.Setenv("HOME", u.HomeDir) // nolint: gosec
|
||||||
os.Setenv("TERM", ttype)
|
_ = os.Setenv("TERM", ttype) // nolint: gosec
|
||||||
os.Setenv("HKEXSH", "1")
|
_ = os.Setenv("HKEXSH", "1") // nolint: gosec
|
||||||
|
|
||||||
var c *exec.Cmd
|
var c *exec.Cmd
|
||||||
cmdName := "/bin/tar"
|
cmdName := "/bin/tar"
|
||||||
|
@ -167,7 +172,7 @@ func runServerToClientCopyAs(who, ttype string, conn *hkexnet.Conn, srcPath stri
|
||||||
srcDir, srcBase := path.Split(srcPath)
|
srcDir, srcBase := path.Split(srcPath)
|
||||||
cmdArgs := []string{"-cz", "-C", srcDir, "-f", "-", srcBase}
|
cmdArgs := []string{"-cz", "-C", srcDir, "-f", "-", srcBase}
|
||||||
|
|
||||||
c = exec.Command(cmdName, cmdArgs...)
|
c = exec.Command(cmdName, cmdArgs...) // nolint: gosec
|
||||||
|
|
||||||
//If os.Clearenv() isn't called by server above these will be seen in the
|
//If os.Clearenv() isn't called by server above these will be seen in the
|
||||||
//client's session env.
|
//client's session env.
|
||||||
|
@ -197,40 +202,44 @@ func runServerToClientCopyAs(who, ttype string, conn *hkexnet.Conn, srcPath stri
|
||||||
err = c.Start() // returns immediately
|
err = c.Start() // returns immediately
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Printf("Command finished with error: %v", err)
|
log.Printf("Command finished with error: %v", err)
|
||||||
return err, hkexnet.CSEExecFail // !?
|
return hkexnet.CSEExecFail, err // !?
|
||||||
} else {
|
}
|
||||||
if err := c.Wait(); err != nil {
|
if err := c.Wait(); err != nil {
|
||||||
//fmt.Println("*** c.Wait() done ***")
|
//fmt.Println("*** c.Wait() done ***")
|
||||||
if exiterr, ok := err.(*exec.ExitError); ok {
|
if exiterr, ok := err.(*exec.ExitError); ok {
|
||||||
// The program has exited with an exit code != 0
|
// The program has exited with an exit code != 0
|
||||||
|
|
||||||
// This works on both Unix and Windows. Although package
|
// This works on both Unix and Windows. Although package
|
||||||
// syscall is generally platform dependent, WaitStatus is
|
// syscall is generally platform dependent, WaitStatus is
|
||||||
// defined for both Unix and Windows and in both cases has
|
// defined for both Unix and Windows and in both cases has
|
||||||
// an ExitStatus() method with the same signature.
|
// an ExitStatus() method with the same signature.
|
||||||
if status, ok := exiterr.Sys().(syscall.WaitStatus); ok {
|
if status, ok := exiterr.Sys().(syscall.WaitStatus); ok {
|
||||||
exitStatus = uint32(status.ExitStatus())
|
exitStatus = uint32(status.ExitStatus())
|
||||||
if len(stdErrBuffer.Bytes()) > 0 {
|
if len(stdErrBuffer.Bytes()) > 0 {
|
||||||
log.Print(stdErrBuffer)
|
log.Print(stdErrBuffer)
|
||||||
}
|
|
||||||
log.Printf("Exit Status: %d", exitStatus)
|
|
||||||
}
|
}
|
||||||
|
log.Printf("Exit Status: %d", exitStatus)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
//fmt.Println("*** server->client cp finished ***")
|
|
||||||
return
|
|
||||||
}
|
}
|
||||||
|
//fmt.Println("*** server->client cp finished ***")
|
||||||
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
// Run a command (via default shell) as a specific user
|
// Run a command (via default shell) as a specific user
|
||||||
//
|
//
|
||||||
// Uses ptys to support commands which expect a terminal.
|
// Uses ptys to support commands which expect a terminal.
|
||||||
func runShellAs(who, ttype string, cmd string, interactive bool, conn *hkexnet.Conn, chaffing bool) (err error, exitStatus uint32) {
|
// nolint: gocyclo
|
||||||
|
func runShellAs(who, ttype string, cmd string, interactive bool, conn *hkexnet.Conn, chaffing bool) (exitStatus uint32, err error) {
|
||||||
var wg sync.WaitGroup
|
var wg sync.WaitGroup
|
||||||
u, _ := user.Lookup(who)
|
u, err := user.Lookup(who)
|
||||||
|
if err != nil {
|
||||||
|
exitStatus = 1
|
||||||
|
return
|
||||||
|
}
|
||||||
var uid, gid uint32
|
var uid, gid uint32
|
||||||
fmt.Sscanf(u.Uid, "%d", &uid)
|
_, _ = fmt.Sscanf(u.Uid, "%d", &uid) // nolint: gosec
|
||||||
fmt.Sscanf(u.Gid, "%d", &gid)
|
_, _ = fmt.Sscanf(u.Gid, "%d", &gid) // nolint: gosec
|
||||||
log.Println("uid:", uid, "gid:", gid)
|
log.Println("uid:", uid, "gid:", gid)
|
||||||
|
|
||||||
// Need to clear server's env and set key vars of the
|
// Need to clear server's env and set key vars of the
|
||||||
|
@ -241,15 +250,15 @@ func runShellAs(who, ttype string, cmd string, interactive bool, conn *hkexnet.C
|
||||||
// of client shell window used to run client.
|
// of client shell window used to run client.
|
||||||
// Investigate -- rlm 2018-01-26)
|
// Investigate -- rlm 2018-01-26)
|
||||||
os.Clearenv()
|
os.Clearenv()
|
||||||
os.Setenv("HOME", u.HomeDir)
|
_ = os.Setenv("HOME", u.HomeDir) // nolint: gosec
|
||||||
os.Setenv("TERM", ttype)
|
_ = os.Setenv("TERM", ttype) // nolint: gosec
|
||||||
os.Setenv("HKEXSH", "1")
|
_ = os.Setenv("HKEXSH", "1") // nolint: gosec
|
||||||
|
|
||||||
var c *exec.Cmd
|
var c *exec.Cmd
|
||||||
if interactive {
|
if interactive {
|
||||||
c = exec.Command("/bin/bash", "-i", "-l")
|
c = exec.Command("/bin/bash", "-i", "-l") // nolint: gosec
|
||||||
} else {
|
} else {
|
||||||
c = exec.Command("/bin/bash", "-c", cmd)
|
c = exec.Command("/bin/bash", "-c", cmd) // nolint: gosec
|
||||||
}
|
}
|
||||||
//If os.Clearenv() isn't called by server above these will be seen in the
|
//If os.Clearenv() isn't called by server above these will be seen in the
|
||||||
//client's session env.
|
//client's session env.
|
||||||
|
@ -264,10 +273,10 @@ func runShellAs(who, ttype string, cmd string, interactive bool, conn *hkexnet.C
|
||||||
// Start the command with a pty.
|
// Start the command with a pty.
|
||||||
ptmx, err := pty.Start(c) // returns immediately with ptmx file
|
ptmx, err := pty.Start(c) // returns immediately with ptmx file
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err, hkexnet.CSEPtyExecFail
|
return hkexnet.CSEPtyExecFail, err
|
||||||
}
|
}
|
||||||
// Make sure to close the pty at the end.
|
// Make sure to close the pty at the end.
|
||||||
defer func() { _ = ptmx.Close() }() // Best effort.
|
defer func() { _ = ptmx.Close() }() // nolint: gosec
|
||||||
|
|
||||||
log.Printf("[%s]\n", cmd)
|
log.Printf("[%s]\n", cmd)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
@ -278,7 +287,7 @@ func runShellAs(who, ttype string, cmd string, interactive bool, conn *hkexnet.C
|
||||||
go func() {
|
go func() {
|
||||||
for sz := range conn.WinCh {
|
for sz := range conn.WinCh {
|
||||||
log.Printf("[Setting term size to: %v %v]\n", sz.Rows, sz.Cols)
|
log.Printf("[Setting term size to: %v %v]\n", sz.Rows, sz.Cols)
|
||||||
pty.Setsize(ptmx, &pty.Winsize{Rows: sz.Rows, Cols: sz.Cols})
|
pty.Setsize(ptmx, &pty.Winsize{Rows: sz.Rows, Cols: sz.Cols}) // nolint: gosec,errcheck
|
||||||
}
|
}
|
||||||
log.Println("*** WinCh goroutine done ***")
|
log.Println("*** WinCh goroutine done ***")
|
||||||
}()
|
}()
|
||||||
|
@ -339,6 +348,8 @@ func runShellAs(who, ttype string, cmd string, interactive bool, conn *hkexnet.C
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// GenAuthToken generates a pseudorandom auth token for a specific
|
||||||
|
// user from a specific host to allow non-interactive logins.
|
||||||
func GenAuthToken(who string, connhost string) string {
|
func GenAuthToken(who string, connhost string) string {
|
||||||
//tokenA, e := os.Hostname()
|
//tokenA, e := os.Hostname()
|
||||||
//if e != nil {
|
//if e != nil {
|
||||||
|
@ -347,7 +358,7 @@ func GenAuthToken(who string, connhost string) string {
|
||||||
tokenA := connhost
|
tokenA := connhost
|
||||||
|
|
||||||
tokenB := make([]byte, 64)
|
tokenB := make([]byte, 64)
|
||||||
_, _ = rand.Read(tokenB)
|
_, _ = rand.Read(tokenB) // nolint: gosec
|
||||||
return fmt.Sprintf("%s:%s", tokenA, hex.EncodeToString(tokenB))
|
return fmt.Sprintf("%s:%s", tokenA, hex.EncodeToString(tokenB))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -356,6 +367,7 @@ func GenAuthToken(who string, connhost string) string {
|
||||||
// server code, save for declaring 'hkex' rather than 'net'
|
// server code, save for declaring 'hkex' rather than 'net'
|
||||||
// Listener and Conns. The KEx and encrypt/decrypt is done within the type.
|
// Listener and Conns. The KEx and encrypt/decrypt is done within the type.
|
||||||
// Compare to 'serverp.go' in this directory to see the equivalence.
|
// Compare to 'serverp.go' in this directory to see the equivalence.
|
||||||
|
// TODO: reduce gocyclo
|
||||||
func main() {
|
func main() {
|
||||||
version := hkexsh.Version
|
version := hkexsh.Version
|
||||||
|
|
||||||
|
@ -388,7 +400,7 @@ func main() {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
Log, _ = logger.New(logger.LOG_DAEMON|logger.LOG_DEBUG|logger.LOG_NOTICE|logger.LOG_ERR, "hkexshd")
|
Log, _ = logger.New(logger.LOG_DAEMON|logger.LOG_DEBUG|logger.LOG_NOTICE|logger.LOG_ERR, "hkexshd") // nolint: gosec
|
||||||
hkexnet.Init(dbg, "hkexshd", logger.LOG_DAEMON|logger.LOG_DEBUG|logger.LOG_NOTICE|logger.LOG_ERR)
|
hkexnet.Init(dbg, "hkexshd", logger.LOG_DAEMON|logger.LOG_DEBUG|logger.LOG_NOTICE|logger.LOG_ERR)
|
||||||
if dbg {
|
if dbg {
|
||||||
log.SetOutput(Log)
|
log.SetOutput(Log)
|
||||||
|
@ -404,17 +416,17 @@ func main() {
|
||||||
sig := <-exitCh
|
sig := <-exitCh
|
||||||
switch sig.String() {
|
switch sig.String() {
|
||||||
case "terminated":
|
case "terminated":
|
||||||
logger.LogNotice(fmt.Sprintf("[Got signal: %s]", sig))
|
logger.LogNotice(fmt.Sprintf("[Got signal: %s]", sig)) // nolint: gosec,errcheck
|
||||||
signal.Reset()
|
signal.Reset()
|
||||||
syscall.Kill(0, syscall.SIGTERM)
|
syscall.Kill(0, syscall.SIGTERM) // nolint: gosec,errcheck
|
||||||
case "interrupt":
|
case "interrupt":
|
||||||
logger.LogNotice(fmt.Sprintf("[Got signal: %s]", sig))
|
logger.LogNotice(fmt.Sprintf("[Got signal: %s]", sig)) // nolint: gosec,errcheck
|
||||||
signal.Reset()
|
signal.Reset()
|
||||||
syscall.Kill(0, syscall.SIGINT)
|
syscall.Kill(0, syscall.SIGINT) // nolint: gosec,errcheck
|
||||||
case "hangup":
|
case "hangup":
|
||||||
logger.LogNotice(fmt.Sprintf("[Got signal: %s - nop]", sig))
|
logger.LogNotice(fmt.Sprintf("[Got signal: %s - nop]", sig)) // nolint:gosec,errcheck
|
||||||
default:
|
default:
|
||||||
logger.LogNotice(fmt.Sprintf("[Got signal: %s - ignored]", sig))
|
logger.LogNotice(fmt.Sprintf("[Got signal: %s - ignored]", sig)) // nolint: gosec,errcheck
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}()
|
}()
|
||||||
|
@ -425,7 +437,7 @@ func main() {
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Fatal(err)
|
log.Fatal(err)
|
||||||
}
|
}
|
||||||
defer l.Close()
|
defer l.Close() // nolint: errcheck
|
||||||
|
|
||||||
log.Println("Serving on", laddr)
|
log.Println("Serving on", laddr)
|
||||||
for {
|
for {
|
||||||
|
@ -445,7 +457,7 @@ func main() {
|
||||||
// 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 *hkexnet.Conn) (e error) {
|
go func(hc *hkexnet.Conn) (e error) {
|
||||||
defer hc.Close()
|
defer hc.Close() // nolint: errcheck
|
||||||
|
|
||||||
//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 hkexsh.Session, and no more.
|
//just the data we want for the hkexsh.Session, and no more.
|
||||||
|
@ -462,7 +474,7 @@ func main() {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
tmp := make([]byte, len1, len1)
|
tmp := make([]byte, len1)
|
||||||
_, err = io.ReadFull(hc, tmp)
|
_, err = io.ReadFull(hc, tmp)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Println("[Bad hkexsh.Session.Op]")
|
log.Println("[Bad hkexsh.Session.Op]")
|
||||||
|
@ -470,7 +482,7 @@ func main() {
|
||||||
}
|
}
|
||||||
rec.SetOp(tmp)
|
rec.SetOp(tmp)
|
||||||
|
|
||||||
tmp = make([]byte, len2, len2)
|
tmp = make([]byte, len2)
|
||||||
_, err = io.ReadFull(hc, tmp)
|
_, err = io.ReadFull(hc, tmp)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Println("[Bad hkexsh.Session.Who]")
|
log.Println("[Bad hkexsh.Session.Who]")
|
||||||
|
@ -478,7 +490,7 @@ func main() {
|
||||||
}
|
}
|
||||||
rec.SetWho(tmp)
|
rec.SetWho(tmp)
|
||||||
|
|
||||||
tmp = make([]byte, len3, len3)
|
tmp = make([]byte, len3)
|
||||||
_, err = io.ReadFull(hc, tmp)
|
_, err = io.ReadFull(hc, tmp)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Println("[Bad hkexsh.Session.ConnHost]")
|
log.Println("[Bad hkexsh.Session.ConnHost]")
|
||||||
|
@ -486,7 +498,7 @@ func main() {
|
||||||
}
|
}
|
||||||
rec.SetConnHost(tmp)
|
rec.SetConnHost(tmp)
|
||||||
|
|
||||||
tmp = make([]byte, len4, len4)
|
tmp = make([]byte, len4)
|
||||||
_, err = io.ReadFull(hc, tmp)
|
_, err = io.ReadFull(hc, tmp)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Println("[Bad hkexsh.Session.TermType]")
|
log.Println("[Bad hkexsh.Session.TermType]")
|
||||||
|
@ -494,7 +506,7 @@ func main() {
|
||||||
}
|
}
|
||||||
rec.SetTermType(tmp)
|
rec.SetTermType(tmp)
|
||||||
|
|
||||||
tmp = make([]byte, len5, len5)
|
tmp = make([]byte, len5)
|
||||||
_, err = io.ReadFull(hc, tmp)
|
_, err = io.ReadFull(hc, tmp)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Println("[Bad hkexsh.Session.Cmd]")
|
log.Println("[Bad hkexsh.Session.Cmd]")
|
||||||
|
@ -502,7 +514,7 @@ func main() {
|
||||||
}
|
}
|
||||||
rec.SetCmd(tmp)
|
rec.SetCmd(tmp)
|
||||||
|
|
||||||
tmp = make([]byte, len6, len6)
|
tmp = make([]byte, len6)
|
||||||
_, err = io.ReadFull(hc, tmp)
|
_, err = io.ReadFull(hc, tmp)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Println("[Bad hkexsh.Session.AuthCookie]")
|
log.Println("[Bad hkexsh.Session.AuthCookie]")
|
||||||
|
@ -526,10 +538,10 @@ func main() {
|
||||||
|
|
||||||
// Tell client if auth was valid
|
// Tell client if auth was valid
|
||||||
if valid {
|
if valid {
|
||||||
hc.Write([]byte{1})
|
hc.Write([]byte{1}) // nolint: gosec,errcheck
|
||||||
} else {
|
} else {
|
||||||
logger.LogNotice(fmt.Sprintln("Invalid user", string(rec.Who())))
|
logger.LogNotice(fmt.Sprintln("Invalid user", string(rec.Who()))) // nolint: errcheck,gosec
|
||||||
hc.Write([]byte{0}) // ? required?
|
hc.Write([]byte{0}) // nolint: gosec,errcheck
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -539,15 +551,15 @@ func main() {
|
||||||
// Generate automated login token
|
// Generate automated login token
|
||||||
addr := hc.RemoteAddr()
|
addr := hc.RemoteAddr()
|
||||||
hname := goutmp.GetHost(addr.String())
|
hname := goutmp.GetHost(addr.String())
|
||||||
logger.LogNotice(fmt.Sprintf("[Generating autologin token for [%s@%s]]\n", rec.Who(), hname))
|
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()))
|
token := GenAuthToken(string(rec.Who()), string(rec.ConnHost()))
|
||||||
tokenCmd := fmt.Sprintf("echo \"%s\" | tee -a ~/.hkexsh_id", token)
|
tokenCmd := fmt.Sprintf("echo \"%s\" | tee -a ~/.hkexsh_id", token)
|
||||||
runErr, cmdStatus := runShellAs(string(rec.Who()), string(rec.TermType()), tokenCmd, false, hc, chaffEnabled)
|
cmdStatus, runErr := runShellAs(string(rec.Who()), string(rec.TermType()), tokenCmd, false, hc, chaffEnabled)
|
||||||
// Returned hopefully via an EOF or exit/logout;
|
// Returned hopefully via an EOF or exit/logout;
|
||||||
// Clear current op so user can enter next, or EOF
|
// Clear current op so user can enter next, or EOF
|
||||||
rec.SetOp([]byte{0})
|
rec.SetOp([]byte{0})
|
||||||
if runErr != nil {
|
if runErr != nil {
|
||||||
logger.LogErr(fmt.Sprintf("[Error generating autologin token for %s@%s]\n", rec.Who(), hname))
|
logger.LogErr(fmt.Sprintf("[Error generating autologin token for %s@%s]\n", rec.Who(), hname)) // nolint: gosec,errcheck
|
||||||
} else {
|
} else {
|
||||||
log.Printf("[Autologin token generation completed for %s@%s, status %d]\n", rec.Who(), hname, cmdStatus)
|
log.Printf("[Autologin token generation completed for %s@%s, status %d]\n", rec.Who(), hname, cmdStatus)
|
||||||
hc.SetStatus(hkexnet.CSOType(cmdStatus))
|
hc.SetStatus(hkexnet.CSOType(cmdStatus))
|
||||||
|
@ -556,34 +568,34 @@ func main() {
|
||||||
// Non-interactive command
|
// Non-interactive command
|
||||||
addr := hc.RemoteAddr()
|
addr := hc.RemoteAddr()
|
||||||
hname := goutmp.GetHost(addr.String())
|
hname := goutmp.GetHost(addr.String())
|
||||||
logger.LogNotice(fmt.Sprintf("[Running command for [%s@%s]]\n", rec.Who(), hname))
|
logger.LogNotice(fmt.Sprintf("[Running command for [%s@%s]]\n", rec.Who(), hname)) // nolint: gosec,errcheck
|
||||||
runErr, cmdStatus := runShellAs(string(rec.Who()), string(rec.TermType()), string(rec.Cmd()), false, hc, chaffEnabled)
|
cmdStatus, runErr := runShellAs(string(rec.Who()), string(rec.TermType()), string(rec.Cmd()), false, hc, chaffEnabled)
|
||||||
// Returned hopefully via an EOF or exit/logout;
|
// Returned hopefully via an EOF or exit/logout;
|
||||||
// Clear current op so user can enter next, or EOF
|
// Clear current op so user can enter next, or EOF
|
||||||
rec.SetOp([]byte{0})
|
rec.SetOp([]byte{0})
|
||||||
if runErr != nil {
|
if runErr != nil {
|
||||||
logger.LogErr(fmt.Sprintf("[Error spawning cmd for %s@%s]\n", rec.Who(), hname))
|
logger.LogErr(fmt.Sprintf("[Error spawning cmd for %s@%s]\n", rec.Who(), hname)) // nolint: gosec,errcheck
|
||||||
} else {
|
} else {
|
||||||
logger.LogNotice(fmt.Sprintf("[Command completed for %s@%s, status %d]\n", rec.Who(), hname, cmdStatus))
|
logger.LogNotice(fmt.Sprintf("[Command completed for %s@%s, status %d]\n", rec.Who(), hname, cmdStatus)) // nolint: gosec,errcheck
|
||||||
hc.SetStatus(hkexnet.CSOType(cmdStatus))
|
hc.SetStatus(hkexnet.CSOType(cmdStatus))
|
||||||
}
|
}
|
||||||
} else if rec.Op()[0] == 's' {
|
} else if rec.Op()[0] == 's' {
|
||||||
// Interactive session
|
// Interactive session
|
||||||
addr := hc.RemoteAddr()
|
addr := hc.RemoteAddr()
|
||||||
hname := goutmp.GetHost(addr.String())
|
hname := goutmp.GetHost(addr.String())
|
||||||
logger.LogNotice(fmt.Sprintf("[Running shell for [%s@%s]]\n", rec.Who(), hname))
|
logger.LogNotice(fmt.Sprintf("[Running shell for [%s@%s]]\n", rec.Who(), hname)) // nolint: gosec,errcheck
|
||||||
|
|
||||||
utmpx := goutmp.Put_utmp(string(rec.Who()), hname)
|
utmpx := goutmp.Put_utmp(string(rec.Who()), hname)
|
||||||
defer func() { goutmp.Unput_utmp(utmpx) }()
|
defer func() { goutmp.Unput_utmp(utmpx) }()
|
||||||
goutmp.Put_lastlog_entry("hkexsh", string(rec.Who()), hname)
|
goutmp.Put_lastlog_entry("hkexsh", string(rec.Who()), hname)
|
||||||
runErr, cmdStatus := runShellAs(string(rec.Who()), string(rec.TermType()), string(rec.Cmd()), true, hc, chaffEnabled)
|
cmdStatus, runErr := runShellAs(string(rec.Who()), string(rec.TermType()), string(rec.Cmd()), true, hc, chaffEnabled)
|
||||||
// Returned hopefully via an EOF or exit/logout;
|
// Returned hopefully via an EOF or exit/logout;
|
||||||
// Clear current op so user can enter next, or EOF
|
// Clear current op so user can enter next, or EOF
|
||||||
rec.SetOp([]byte{0})
|
rec.SetOp([]byte{0})
|
||||||
if runErr != nil {
|
if runErr != nil {
|
||||||
Log.Err(fmt.Sprintf("[Error spawning shell for %s@%s]\n", rec.Who(), hname))
|
Log.Err(fmt.Sprintf("[Error spawning shell for %s@%s]\n", rec.Who(), hname)) // nolint: gosec,errcheck
|
||||||
} else {
|
} else {
|
||||||
logger.LogNotice(fmt.Sprintf("[Shell completed for %s@%s, status %d]\n", rec.Who(), hname, cmdStatus))
|
logger.LogNotice(fmt.Sprintf("[Shell completed for %s@%s, status %d]\n", rec.Who(), hname, cmdStatus)) // nolint: gosec,errcheck
|
||||||
hc.SetStatus(hkexnet.CSOType(cmdStatus))
|
hc.SetStatus(hkexnet.CSOType(cmdStatus))
|
||||||
}
|
}
|
||||||
} else if rec.Op()[0] == 'D' {
|
} else if rec.Op()[0] == 'D' {
|
||||||
|
@ -591,15 +603,15 @@ func main() {
|
||||||
log.Printf("[Client->Server copy]\n")
|
log.Printf("[Client->Server copy]\n")
|
||||||
addr := hc.RemoteAddr()
|
addr := hc.RemoteAddr()
|
||||||
hname := goutmp.GetHost(addr.String())
|
hname := goutmp.GetHost(addr.String())
|
||||||
logger.LogNotice(fmt.Sprintf("[Running copy for [%s@%s]]\n", rec.Who(), hname))
|
logger.LogNotice(fmt.Sprintf("[Running copy for [%s@%s]]\n", rec.Who(), hname)) // nolint: gosec,errcheck
|
||||||
runErr, cmdStatus := runClientToServerCopyAs(string(rec.Who()), string(rec.TermType()), hc, string(rec.Cmd()), chaffEnabled)
|
cmdStatus, runErr := runClientToServerCopyAs(string(rec.Who()), string(rec.TermType()), hc, string(rec.Cmd()), chaffEnabled)
|
||||||
// Returned hopefully via an EOF or exit/logout;
|
// Returned hopefully via an EOF or exit/logout;
|
||||||
// Clear current op so user can enter next, or EOF
|
// Clear current op so user can enter next, or EOF
|
||||||
rec.SetOp([]byte{0})
|
rec.SetOp([]byte{0})
|
||||||
if runErr != nil {
|
if runErr != nil {
|
||||||
logger.LogErr(fmt.Sprintf("[Error running cp for %s@%s]\n", rec.Who(), hname))
|
logger.LogErr(fmt.Sprintf("[Error running cp for %s@%s]\n", rec.Who(), hname)) // nolint: gosec,errcheck
|
||||||
} else {
|
} else {
|
||||||
logger.LogNotice(fmt.Sprintf("[Command completed for %s@%s, status %d]\n", rec.Who(), hname, cmdStatus))
|
logger.LogNotice(fmt.Sprintf("[Command completed for %s@%s, status %d]\n", rec.Who(), hname, cmdStatus)) // nolint: gosec,errcheck
|
||||||
}
|
}
|
||||||
hc.SetStatus(hkexnet.CSOType(cmdStatus))
|
hc.SetStatus(hkexnet.CSOType(cmdStatus))
|
||||||
|
|
||||||
|
@ -607,32 +619,32 @@ func main() {
|
||||||
s := make([]byte, 4)
|
s := make([]byte, 4)
|
||||||
binary.BigEndian.PutUint32(s, cmdStatus)
|
binary.BigEndian.PutUint32(s, cmdStatus)
|
||||||
log.Printf("** cp writing closeStat %d at Close()\n", cmdStatus)
|
log.Printf("** cp writing closeStat %d at Close()\n", cmdStatus)
|
||||||
hc.WritePacket(s, hkexnet.CSOExitStatus)
|
hc.WritePacket(s, hkexnet.CSOExitStatus) // nolint: gosec,errcheck
|
||||||
} else if rec.Op()[0] == 'S' {
|
} else if rec.Op()[0] == 'S' {
|
||||||
// File copy (src) operation - server copy to client
|
// File copy (src) operation - server copy to client
|
||||||
log.Printf("[Server->Client copy]\n")
|
log.Printf("[Server->Client copy]\n")
|
||||||
addr := hc.RemoteAddr()
|
addr := hc.RemoteAddr()
|
||||||
hname := goutmp.GetHost(addr.String())
|
hname := goutmp.GetHost(addr.String())
|
||||||
logger.LogNotice(fmt.Sprintf("[Running copy for [%s@%s]]\n", rec.Who(), hname))
|
logger.LogNotice(fmt.Sprintf("[Running copy for [%s@%s]]\n", rec.Who(), hname)) // nolint: gosec,errcheck
|
||||||
runErr, cmdStatus := runServerToClientCopyAs(string(rec.Who()), string(rec.TermType()), hc, string(rec.Cmd()), chaffEnabled)
|
cmdStatus, runErr := runServerToClientCopyAs(string(rec.Who()), string(rec.TermType()), hc, string(rec.Cmd()), chaffEnabled)
|
||||||
// Returned hopefully via an EOF or exit/logout;
|
if runErr != nil {
|
||||||
|
logger.LogErr(fmt.Sprintf("[Error spawning cp for %s@%s]\n", rec.Who(), hname)) // nolint: gosec,errcheck
|
||||||
|
} else {
|
||||||
|
// Returned hopefully via an EOF or exit/logout;
|
||||||
|
logger.LogNotice(fmt.Sprintf("[Command completed for %s@%s, status %d]\n", rec.Who(), hname, cmdStatus)) // nolint: gosec,errcheck
|
||||||
|
}
|
||||||
// Clear current op so user can enter next, or EOF
|
// Clear current op so user can enter next, or EOF
|
||||||
rec.SetOp([]byte{0})
|
rec.SetOp([]byte{0})
|
||||||
if runErr != nil {
|
|
||||||
logger.LogErr(fmt.Sprintf("[Error spawning cp for %s@%s]\n", rec.Who(), hname))
|
|
||||||
} else {
|
|
||||||
logger.LogNotice(fmt.Sprintf("[Command completed for %s@%s, status %d]\n", rec.Who(), hname, cmdStatus))
|
|
||||||
}
|
|
||||||
hc.SetStatus(hkexnet.CSOType(cmdStatus))
|
hc.SetStatus(hkexnet.CSOType(cmdStatus))
|
||||||
//fmt.Println("Waiting for EOF from other end.")
|
//fmt.Println("Waiting for EOF from other end.")
|
||||||
//_, _ = hc.Read(nil /*ackByte*/)
|
//_, _ = hc.Read(nil /*ackByte*/)
|
||||||
//fmt.Println("Got remote end ack.")
|
//fmt.Println("Got remote end ack.")
|
||||||
} else {
|
} else {
|
||||||
logger.LogErr(fmt.Sprintln("[Bad hkexsh.Session]"))
|
logger.LogErr(fmt.Sprintln("[Bad hkexsh.Session]")) // nolint: gosec,errcheck
|
||||||
}
|
}
|
||||||
return
|
return
|
||||||
}(&conn)
|
}(&conn) // nolint: errcheck
|
||||||
} // Accept() success
|
} // Accept() success
|
||||||
} //endfor
|
} //endfor
|
||||||
logger.LogNotice(fmt.Sprintln("[Exiting]"))
|
//logger.LogNotice(fmt.Sprintln("[Exiting]")) // nolint: gosec,errcheck
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
.PHONY: clean all
|
.PHONY: clean all lint
|
||||||
|
|
||||||
EXE = $(notdir $(shell pwd))
|
EXE = $(notdir $(shell pwd))
|
||||||
|
|
||||||
|
@ -8,3 +8,5 @@ all:
|
||||||
clean:
|
clean:
|
||||||
$(RM) $(EXE) $(EXE).exe
|
$(RM) $(EXE) $(EXE).exe
|
||||||
|
|
||||||
|
lint:
|
||||||
|
gometalinter --deadline 60s | sort
|
||||||
|
|
|
@ -1,17 +1,20 @@
|
||||||
// +build linux
|
// +build linux
|
||||||
//
|
|
||||||
// Wrapper around UNIX syslog, so that it also may be wrapped
|
// Package logger is a wrapper around UNIX syslog, so that it also may
|
||||||
// with something else for Windows (Sadly, the stdlib log/syslog
|
// be wrapped with something else for Windows (Sadly, the stdlib log/syslog
|
||||||
// is frozen, and there is no Window implementation.)
|
// is frozen, and there is no Windows implementation.)
|
||||||
package logger
|
package logger
|
||||||
|
|
||||||
import (
|
import (
|
||||||
sl "log/syslog"
|
sl "log/syslog"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
// Priority is the logger priority
|
||||||
type Priority = sl.Priority
|
type Priority = sl.Priority
|
||||||
|
// Writer is a syslog Writer
|
||||||
type Writer = sl.Writer
|
type Writer = sl.Writer
|
||||||
|
|
||||||
|
// nolint: golint
|
||||||
const (
|
const (
|
||||||
// Severity.
|
// Severity.
|
||||||
|
|
||||||
|
@ -27,6 +30,7 @@ const (
|
||||||
LOG_DEBUG
|
LOG_DEBUG
|
||||||
)
|
)
|
||||||
|
|
||||||
|
// nolint: golint
|
||||||
const (
|
const (
|
||||||
// Facility.
|
// Facility.
|
||||||
|
|
||||||
|
@ -62,39 +66,59 @@ var (
|
||||||
l *sl.Writer
|
l *sl.Writer
|
||||||
)
|
)
|
||||||
|
|
||||||
|
// New returns a new log Writer.
|
||||||
func New(flags Priority, tag string) (w *Writer, e error) {
|
func New(flags Priority, tag string) (w *Writer, e error) {
|
||||||
w, e = sl.New(sl.Priority(flags), tag)
|
w, e = sl.New(flags, tag)
|
||||||
l = w
|
l = w
|
||||||
return w, e
|
return w, e
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Alert returns a log Alert error
|
||||||
func Alert(s string) error {
|
func Alert(s string) error {
|
||||||
return l.Alert(s)
|
return l.Alert(s)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// LogClose closes the log Writer.
|
||||||
func LogClose() error {
|
func LogClose() error {
|
||||||
return l.Close()
|
return l.Close()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// LogCrit returns a log Alert error
|
||||||
func LogCrit(s string) error {
|
func LogCrit(s string) error {
|
||||||
return l.Crit(s)
|
return l.Crit(s)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// LogDebug returns a log Debug error
|
||||||
func LogDebug(s string) error {
|
func LogDebug(s string) error {
|
||||||
return l.Debug(s)
|
return l.Debug(s)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// LogEmerg returns a log Emerg error
|
||||||
func LogEmerg(s string) error {
|
func LogEmerg(s string) error {
|
||||||
return l.Emerg(s)
|
return l.Emerg(s)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// LogErr returns a log Err error
|
||||||
func LogErr(s string) error {
|
func LogErr(s string) error {
|
||||||
return l.Err(s)
|
return l.Err(s)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// LogInfo returns a log Info error
|
||||||
func LogInfo(s string) error {
|
func LogInfo(s string) error {
|
||||||
return l.Info(s)
|
return l.Info(s)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// LogNotice returns a log Notice error
|
||||||
func LogNotice(s string) error {
|
func LogNotice(s string) error {
|
||||||
return l.Notice(s)
|
return l.Notice(s)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// LogWarning returns a log Warning error
|
||||||
func LogWarning(s string) error {
|
func LogWarning(s string) error {
|
||||||
return l.Warning(s)
|
return l.Warning(s)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// LogWrite writes to the logger at default level
|
||||||
func LogWrite(b []byte) (int, error) {
|
func LogWrite(b []byte) (int, error) {
|
||||||
return l.Write(b)
|
return l.Write(b)
|
||||||
}
|
}
|
||||||
|
|
|
@ -20,6 +20,7 @@ const ioctlReadTermios = unix.TCGETS
|
||||||
const ioctlWriteTermios = unix.TCSETS
|
const ioctlWriteTermios = unix.TCSETS
|
||||||
|
|
||||||
// From github.com/golang/crypto/blob/master/ssh/terminal/util.go
|
// From github.com/golang/crypto/blob/master/ssh/terminal/util.go
|
||||||
|
|
||||||
// State contains the state of a terminal.
|
// State contains the state of a terminal.
|
||||||
type State struct {
|
type State struct {
|
||||||
termios unix.Termios
|
termios unix.Termios
|
||||||
|
@ -87,7 +88,7 @@ func ReadPassword(fd int) ([]byte, error) {
|
||||||
}
|
}
|
||||||
|
|
||||||
defer func() {
|
defer func() {
|
||||||
unix.IoctlSetTermios(fd, ioctlWriteTermios, termios)
|
_ = unix.IoctlSetTermios(fd, ioctlWriteTermios, termios) // nolint: gosec
|
||||||
}()
|
}()
|
||||||
|
|
||||||
return readPasswordLine(passwordReader(fd))
|
return readPasswordLine(passwordReader(fd))
|
||||||
|
|
Loading…
Reference in a new issue