mirror of https://gogs.blitter.com/RLabs/xs
				
				
				
			Gometalinter cleanup/audit of hkexsh, hkexshd, hkexpasswd
Signed-off-by: Russ Magee <rmagee@gmail.com>
This commit is contained in:
		
							parent
							
								
									fa398159e3
								
							
						
					
					
						commit
						6fbbcdadb6
					
				
							
								
								
									
										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 New Issue